mruby/c VM Source Code release 3.4
Loading...
Searching...
No Matches
alloc.c
Go to the documentation of this file.
1
43
44/***** Feature test switches ************************************************/
45/***** System headers *******************************************************/
46//@cond
47#include "vm_config.h"
48#include <stdint.h>
49#include <string.h>
50#include <assert.h>
51//@endcond
52
53#if !defined(MRBC_ALLOC_LIBC)
54/***** Local headers ********************************************************/
55#include "alloc.h"
56#include "hal.h"
57#if defined(MRBC_DEBUG)
58#include "console.h"
59#endif
60
61/***** Constant values ******************************************************/
62/*
63 Layer 1st(f) and 2nd(s) model
64 last 4bit is ignored
65
66 FLI range SLI0 1 2 3 4 5 6 7 BlockSize
67 0 0000-007f unused 0010- 0020- 0030- 0040- 0050- 0060- 0070-007f 16
68 1 0080-00ff 0080- 0090- 00a0- 00b0- 00c0- 00d0- 00e0- 00f0-00ff 16
69 2 0100-01ff 0100- 0120- 0140- 0160- 0180- 01a0- 01c0- 01e0-01ff 32
70 3 0200-03ff 0200- 0240- 0280- 02c0- 0300- 0340- 0380- 03c0-03ff 64
71 4 0400-07ff 0400- 0480- 0500- 0580- 0600- 0680- 0700- 0780-07ff 128
72 5 0800-0fff 0800- 0900- 0a00- 0b00- 0c00- 0d00- 0e00- 0f00-0fff 256
73 6 1000-1fff 1000- 1200- 1400- 1600- 1800- 1a00- 1c00- 1e00-1fff 512
74 7 2000-3fff 2000- 2400- 2800- 2c00- 3000- 3400- 3800- 3c00-3fff 1024
75 8 4000-7fff 4000- 4800- 5000- 5800- 6000- 6800- 7000- 7800-7fff 2048
76 9 8000-ffff 8000- 9000- a000- b000- c000- d000- e000- f000-ffff 4096
77*/
78
79#ifndef MRBC_ALLOC_FLI_BIT_WIDTH // 0000 0000 0000 0000
80# define MRBC_ALLOC_FLI_BIT_WIDTH 9 // ~~~~~~~~~~~
81#endif
82#ifndef MRBC_ALLOC_SLI_BIT_WIDTH // 0000 0000 0000 0000
83# define MRBC_ALLOC_SLI_BIT_WIDTH 3 // ~~~
84#endif
85#ifndef MRBC_ALLOC_IGNORE_LSBS // 0000 0000 0000 0000
86# define MRBC_ALLOC_IGNORE_LSBS 4 // ~~~~
87#endif
88
89#define SIZE_FREE_BLOCKS \
90 ((MRBC_ALLOC_FLI_BIT_WIDTH + 1) * (1 << MRBC_ALLOC_SLI_BIT_WIDTH))
91 // maybe 80 (0x50)
92/*
93 Minimum memory block size parameter.
94 Choose large one from sizeof(FREE_BLOCK) or (1 << MRBC_ALLOC_IGNORE_LSBS)
95*/
96#if !defined(MRBC_MIN_MEMORY_BLOCK_SIZE)
97#define MRBC_MIN_MEMORY_BLOCK_SIZE sizeof(FREE_BLOCK)
98// #define MRBC_MIN_MEMORY_BLOCK_SIZE (1 << MRBC_ALLOC_IGNORE_LSBS)
99#endif
100
101
102/***** Macros ***************************************************************/
103#define FLI(x) ((x) >> MRBC_ALLOC_SLI_BIT_WIDTH)
104#define SLI(x) ((x) & ((1 << MRBC_ALLOC_SLI_BIT_WIDTH) - 1))
105
106
107/***** Typedefs *************************************************************/
108/*
109 define memory block header for 16 bit
110
111 (note)
112 Typical size of
113 USED_BLOCK is 2 bytes
114 FREE_BLOCK is 8 bytes
115 on 16bit machine.
116*/
117#if defined(MRBC_ALLOC_16BIT)
118#define MRBC_ALLOC_MEMSIZE_T uint16_t
119
120typedef struct USED_BLOCK {
121 MRBC_ALLOC_MEMSIZE_T size;
122#if defined(MRBC_ALLOC_VMID)
123 uint8_t vm_id;
124#endif
125} USED_BLOCK;
126
127typedef struct FREE_BLOCK {
128 MRBC_ALLOC_MEMSIZE_T size;
129#if defined(MRBC_ALLOC_VMID)
130 uint8_t vm_id;
131#endif
132
133 struct FREE_BLOCK *next_free;
134 struct FREE_BLOCK *prev_free;
135 struct FREE_BLOCK *top_adrs;
136} FREE_BLOCK;
137
138
139/*
140 define memory block header for 24/32 bit.
141
142 (note)
143 Typical size of
144 USED_BLOCK is 4 bytes
145 FREE_BLOCK is 16 bytes
146 on 32bit machine.
147*/
148#elif defined(MRBC_ALLOC_24BIT)
149#define MRBC_ALLOC_MEMSIZE_T uint32_t
150
151typedef struct USED_BLOCK {
152#if defined(MRBC_ALLOC_VMID)
153 MRBC_ALLOC_MEMSIZE_T size : 24;
154 uint8_t vm_id : 8;
155#else
156 MRBC_ALLOC_MEMSIZE_T size;
157#endif
158} USED_BLOCK;
159
160typedef struct FREE_BLOCK {
161#if defined(MRBC_ALLOC_VMID)
162 MRBC_ALLOC_MEMSIZE_T size : 24;
163 uint8_t vm_id : 8;
164#else
165 MRBC_ALLOC_MEMSIZE_T size;
166#endif
167
168 struct FREE_BLOCK *next_free;
169 struct FREE_BLOCK *prev_free;
170 struct FREE_BLOCK *top_adrs;
171} FREE_BLOCK;
172
173#else
174# error 'define MRBC_ALLOC_*' required.
175#endif
176
177/*
178 and operation macro
179*/
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))
190
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)
194
195#else
196#define SET_VM_ID(p,id) ((void)0)
197#define GET_VM_ID(p) 0
198#endif
199
200
201/*
202 define memory pool header
203*/
204typedef struct MEMORY_POOL {
205 MRBC_ALLOC_MEMSIZE_T size;
206
207 // free memory bitmap
210 // +1=bit_width, +1=sentinel
211 uint8_t pad[3]; // for alignment compatibility on 16bit and 32bit machines
212
213 // free memory block index
214 FREE_BLOCK *free_blocks[SIZE_FREE_BLOCKS +1]; // +1=sentinel
216
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)))
220
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)
225
226
227/***** Function prototypes **************************************************/
228/***** Local variables ******************************************************/
229// memory pool
231
232#if defined(MRBC_USE_ALLOC_PROF)
233static int profiling = 0;
234static struct MRBC_ALLOC_PROF alloc_prof = {0, 0, 0};
235#endif
236
237/***** Global variables *****************************************************/
238/***** Signal catching functions ********************************************/
239/***** Local functions ******************************************************/
240//================================================================
246static inline int nlz16(uint16_t x)
247{
248 if( x == 0 ) return 16;
249
250 int n = 1;
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);
255}
256
257
258//================================================================
264static inline int nlz8(uint8_t x)
265{
266 if( x == 0 ) return 8;
267
268 int n = 1;
269 if((x >> 4) == 0 ) { n += 4; x <<= 4; }
270 if((x >> 6) == 0 ) { n += 2; x <<= 2; }
271 return n - (x >> 7);
272}
273
274
275//================================================================
281static inline unsigned int calc_index(MRBC_ALLOC_MEMSIZE_T alloc_size)
282{
283 // check overflow
284 if( (alloc_size >> (MRBC_ALLOC_FLI_BIT_WIDTH
286 + MRBC_ALLOC_IGNORE_LSBS)) != 0) {
287 return SIZE_FREE_BLOCKS - 1;
288 }
289
290 // calculate First Level Index.
291 unsigned int fli = 16 -
293
294 // calculate Second Level Index.
295 unsigned int shift = (fli == 0) ? MRBC_ALLOC_IGNORE_LSBS :
296 (MRBC_ALLOC_IGNORE_LSBS - 1 + fli);
297
298 unsigned int sli = (alloc_size >> shift) & ((1 << MRBC_ALLOC_SLI_BIT_WIDTH) - 1);
299 unsigned int index = (fli << MRBC_ALLOC_SLI_BIT_WIDTH) + sli;
300
301 assert(fli <= MRBC_ALLOC_FLI_BIT_WIDTH);
302 assert(sli <= (1 << MRBC_ALLOC_SLI_BIT_WIDTH) - 1);
303
304 return index;
305}
306
307
308//================================================================
314static void add_free_block(MEMORY_POOL *pool, FREE_BLOCK *target)
315{
316 SET_FREE_BLOCK(target);
317
318 FREE_BLOCK **top_adrs = (FREE_BLOCK **)((uint8_t*)target + BLOCK_SIZE(target) - sizeof(FREE_BLOCK *));
319 *top_adrs = target;
320
321 unsigned int index = calc_index(BLOCK_SIZE(target));
322 unsigned int fli = FLI(index);
323 unsigned int sli = SLI(index);
324 assert( index < SIZE_FREE_BLOCKS );
325
326 pool->free_fli_bitmap |= (MSB_BIT1_FLI >> fli);
327 pool->free_sli_bitmap[fli] |= (MSB_BIT1_SLI >> sli);
328
329 target->prev_free = NULL;
330 target->next_free = pool->free_blocks[index];
331 if( target->next_free != NULL ) {
332 target->next_free->prev_free = target;
333 }
334 pool->free_blocks[index] = target;
335}
336
337
338//================================================================
344static void remove_free_block(MEMORY_POOL *pool, FREE_BLOCK *target)
345{
346 // top of linked list?
347 if( target->prev_free == NULL ) {
348 unsigned int index = calc_index(BLOCK_SIZE(target));
349
350 pool->free_blocks[index] = target->next_free;
351 if( target->next_free == NULL ) {
352 unsigned int fli = FLI(index);
353 unsigned int sli = SLI(index);
354 pool->free_sli_bitmap[fli] &= ~(MSB_BIT1_SLI >> sli);
355 if( pool->free_sli_bitmap[fli] == 0 ) pool->free_fli_bitmap &= ~(MSB_BIT1_FLI >> fli);
356 }
357 }
358 else {
359 target->prev_free->next_free = target->next_free;
360 }
361
362 if( target->next_free != NULL ) {
363 target->next_free->prev_free = target->prev_free;
364 }
365}
366
367
368#if defined(MRBC_USE_ALLOC_PROF)
369//================================================================
372static void alloc_profile(void)
373{
374 if (!profiling) return;
375
376 MEMORY_POOL *pool = memory_pool;
377 USED_BLOCK *block = BPOOL_TOP(pool);
378 unsigned int used = 0;
379
380 while (block < (USED_BLOCK *)BPOOL_END(pool)) {
381 if (!IS_FREE_BLOCK(block)) {
382 used += BLOCK_SIZE(block);
383 }
384 block = PHYS_NEXT(block);
385 }
386
387 if (alloc_prof.max < used) alloc_prof.max = used;
388 if (used < alloc_prof.min) alloc_prof.min = used;
389}
390#endif
391
392//================================================================
400static inline FREE_BLOCK* split_block(FREE_BLOCK *target, MRBC_ALLOC_MEMSIZE_T size)
401{
402 assert( BLOCK_SIZE(target) >= size );
403 if( (BLOCK_SIZE(target) - size) <= MRBC_MIN_MEMORY_BLOCK_SIZE ) return NULL;
404
405 // split block, free
406 FREE_BLOCK *split = (FREE_BLOCK *)((uint8_t *)target + size);
407
408 split->size = BLOCK_SIZE(target) - size;
409 target->size = size | (target->size & 0x03); // copy a size with flags.
410
411 return split;
412}
413
414
415//================================================================
422static inline void merge_block(FREE_BLOCK *target, FREE_BLOCK *next)
423{
424 assert(target < next);
425
426 // merge target and next
427 target->size += BLOCK_SIZE(next); // copy a size but save flags.
428}
429
430
431/***** Global functions *****************************************************/
432//================================================================
438void mrbc_init_alloc(void *ptr, unsigned int size)
439{
440 assert( MRBC_MIN_MEMORY_BLOCK_SIZE >= sizeof(FREE_BLOCK) );
442 /*
443 If you get this assertion, you can change minimum memory block size
444 parameter to `MRBC_MIN_MEMORY_BLOCK_SIZE (1 << MRBC_ALLOC_IGNORE_LSBS)`
445 and #define MRBC_ALLOC_16BIT.
446 */
447
448 assert( (sizeof(MEMORY_POOL) & 0x03) == 0 );
449#if defined(UINTPTR_MAX)
450 assert( ((uintptr_t)ptr & 0x03) == 0 );
451#else
452 assert( ((uint32_t)ptr & 0x03) == 0 );
453#endif
454 assert( size != 0 );
455 assert( size <= (MRBC_ALLOC_MEMSIZE_T)(~0) );
456
457 size &= ~(unsigned int)0x03; // align 4 byte.
458 memory_pool = ptr;
459 memset( memory_pool, 0, sizeof(MEMORY_POOL) );
460 memory_pool->size = size;
461
462 // initialize memory pool
463 // large free block + zero size used block (sentinel).
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;
467 FREE_BLOCK *free_block = BPOOL_TOP(memory_pool);
468 USED_BLOCK *used_block = (USED_BLOCK *)((uint8_t *)free_block + free_size);
469
470 free_block->size = free_size | 0x02; // flag prev=1, used=0
471 used_block->size = sentinel_size | 0x01; // flag prev=0, used=1
472 SET_VM_ID( used_block, 0xff );
473
474 add_free_block( memory_pool, free_block );
475}
476
477
478//================================================================
482{
483#if defined(MRBC_DEBUG)
484 if( memory_pool ) {
485 memset( memory_pool, 0, memory_pool->size );
486 }
487#endif
488
489 memory_pool = 0;
490}
491
492
493//================================================================
500void * mrbc_raw_alloc(unsigned int size)
501{
502 MEMORY_POOL *pool = memory_pool;
503 MRBC_ALLOC_MEMSIZE_T alloc_size = size + sizeof(USED_BLOCK);
504
505 // align 4 byte
506 alloc_size += (-alloc_size & 3);
507
508 // check minimum alloc size.
509 if( alloc_size < MRBC_MIN_MEMORY_BLOCK_SIZE ) alloc_size = MRBC_MIN_MEMORY_BLOCK_SIZE;
510
511 FREE_BLOCK *target;
512 unsigned int fli, sli;
513 unsigned int index = calc_index(alloc_size);
514
515 // At first, check only the beginning of the same size block.
516 // because it immediately responds to the pattern in which
517 // same size memory are allocated and released continuously.
518 target = pool->free_blocks[index];
519 if( target && BLOCK_SIZE(target) >= alloc_size ) {
520 fli = FLI(index);
521 sli = SLI(index);
522 goto FOUND_TARGET_BLOCK;
523 }
524
525 // and then, check the next (larger) size block.
526 target = pool->free_blocks[++index];
527 fli = FLI(index);
528 sli = SLI(index);
529 if( target ) goto FOUND_TARGET_BLOCK;
530
531 // check in SLI bitmap table.
532 uint16_t masked = pool->free_sli_bitmap[fli] & ((MSB_BIT1_SLI >> sli) - 1);
533 if( masked != 0 ) {
534 sli = NLZ_SLI( masked );
535 goto FOUND_FLI_SLI;
536 }
537
538 // check in FLI bitmap table.
539 masked = pool->free_fli_bitmap & ((MSB_BIT1_FLI >> fli) - 1);
540 if( masked != 0 ) {
541 fli = NLZ_FLI( masked );
542 sli = NLZ_SLI( pool->free_sli_bitmap[fli] );
543 goto FOUND_FLI_SLI;
544 }
545
546 // Change strategy to First-fit.
547 target = pool->free_blocks[--index];
548 while( target ) {
549 if( BLOCK_SIZE(target) >= alloc_size ) {
550 remove_free_block( pool, target );
551 goto SPLIT_BLOCK;
552 }
553 target = target->next_free;
554 }
555
556 // else out of memory
557#if defined(MRBC_OUT_OF_MEMORY)
558 MRBC_OUT_OF_MEMORY();
559#else
560 static const char msg[] = "Fatal error: Out of memory.\n";
561 hal_write(2, msg, sizeof(msg)-1);
562#endif
563 return NULL; // ENOMEM
564
565
566 FOUND_FLI_SLI:
567 index = (fli << MRBC_ALLOC_SLI_BIT_WIDTH) + sli;
568 assert( index < SIZE_FREE_BLOCKS );
569 target = pool->free_blocks[index];
570 assert( target != NULL );
571
572 FOUND_TARGET_BLOCK:
573 assert(BLOCK_SIZE(target) >= alloc_size);
574
575 // remove free_blocks index
576 pool->free_blocks[index] = target->next_free;
577 if( target->next_free == NULL ) {
578 pool->free_sli_bitmap[fli] &= ~(MSB_BIT1_SLI >> sli);
579 if( pool->free_sli_bitmap[fli] == 0 ) pool->free_fli_bitmap &= ~(MSB_BIT1_FLI >> fli);
580 }
581 else {
582 target->next_free->prev_free = NULL;
583 }
584
585 SPLIT_BLOCK: {
586 FREE_BLOCK *release = split_block(target, alloc_size);
587 if( release != NULL ) {
588 SET_PREV_USED(release);
589 add_free_block( pool, release );
590 } else {
591 FREE_BLOCK *next = PHYS_NEXT(target);
592 SET_PREV_USED(next);
593 }
594 }
595
596 SET_USED_BLOCK(target);
597 SET_VM_ID( target, 0 );
598
599#if defined(MRBC_DEBUG)
600 memset( (uint8_t *)target + sizeof(USED_BLOCK), 0xaa,
601 BLOCK_SIZE(target) - sizeof(USED_BLOCK) );
602#endif
603
604#if defined(MRBC_USE_ALLOC_PROF)
605 alloc_profile();
606#endif
607
608 return (uint8_t *)target + sizeof(USED_BLOCK);
609}
610
611
612//================================================================
619void * mrbc_raw_alloc_no_free(unsigned int size)
620{
621 MEMORY_POOL *pool = memory_pool;
622 MRBC_ALLOC_MEMSIZE_T alloc_size = size + (-size & 3); // align 4 byte
623
624 // find the tail block
625 FREE_BLOCK *tail = BPOOL_TOP(pool);
626 FREE_BLOCK *prev;
627 do {
628 prev = tail;
629 tail = PHYS_NEXT(tail);
630 } while( PHYS_NEXT(tail) < BPOOL_END(pool) );
631
632 // can resize it block?
633 if( IS_USED_BLOCK(prev) ) goto FALLBACK;
634 if( (BLOCK_SIZE(prev) - sizeof(USED_BLOCK)) < alloc_size ) goto FALLBACK;
635
636 remove_free_block( pool, prev );
637 MRBC_ALLOC_MEMSIZE_T free_size = BLOCK_SIZE(prev) - alloc_size;
638
639 if( free_size <= MRBC_MIN_MEMORY_BLOCK_SIZE ) {
640 // no split, use all
641 prev->size += BLOCK_SIZE(tail);
642 SET_USED_BLOCK( prev );
643 tail = prev;
644 }
645 else {
646 // split block
647 MRBC_ALLOC_MEMSIZE_T tail_size = tail->size + alloc_size; // w/ flags.
648 tail = (FREE_BLOCK*)((uint8_t *)tail - alloc_size);
649 tail->size = tail_size;
650 prev->size -= alloc_size; // w/ flags.
651 add_free_block( pool, prev );
652
653#if defined(MRBC_DEBUG)
654 memset( (uint8_t *)tail + sizeof(USED_BLOCK), 0xaa, alloc_size );
655#endif
656 }
657 SET_VM_ID( tail, 0xff );
658
659 return (uint8_t *)tail + sizeof(USED_BLOCK);
660
661 FALLBACK:
662 return mrbc_raw_alloc(alloc_size);
663}
664
665
666//================================================================
674void * mrbc_raw_calloc(unsigned int nmemb, unsigned int size)
675{
676 unsigned int total_size = nmemb * size;
677 void* ptr = mrbc_raw_alloc(total_size);
678 if (ptr != NULL) {
679 // Instead of using memset and memset_s (not available in C99),
680 // we use a volatile pointer to prevent unexpected optimization.
681 volatile unsigned char *vptr = (volatile unsigned char *)ptr;
682 while (total_size--) {
683 *vptr++ = 0;
684 }
685 }
686 return ptr;
687}
688
689
690//================================================================
695void mrbc_raw_free(void *ptr)
696{
697 MEMORY_POOL *pool = memory_pool;
698
699#if defined(MRBC_DEBUG)
700 {
701 if( ptr == NULL ) {
702 static const char msg[] = "mrbc_raw_free(): NULL pointer was given.\n";
703 hal_write(2, msg, sizeof(msg)-1);
704 return;
705 }
706
707 FREE_BLOCK *target = BLOCK_ADRS(ptr);
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);
712 return;
713 }
714
715 FREE_BLOCK *block = BPOOL_TOP(pool);
716 while(1) {
717 if( block == target ) break;
718 if( PHYS_NEXT(block) >= BPOOL_END(pool) ) break;
719 block = PHYS_NEXT(block);
720 }
721
722 if( block == target ) {
723 // found target block.
724 if( IS_FREE_BLOCK(block) ) { // is Free block?
725 static const char msg[] = "mrbc_raw_free(): double free detected.\n";
726 hal_write(2, msg, sizeof(msg)-1);
727 return;
728 }
729
730 if( PHYS_NEXT(block) >= BPOOL_END(pool) ) { // Is this a sentinel?
731 static const char msg[] = "mrbc_raw_free(): no_free address was specified.\n";
732 hal_write(2, msg, sizeof(msg)-1);
733 return;
734 }
735
736 } else {
737 // not found target block.
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);
741 return;
742 }
743
744 static const char msg[] = "mrbc_raw_free(): Illegal address.\n";
745 hal_write(2, msg, sizeof(msg)-1);
746 return;
747 }
748
749 SET_VM_ID( target, 0xff );
750 memset( ptr, 0xff, BLOCK_SIZE(target) - sizeof(USED_BLOCK) );
751 }
752#endif
753
754 if( ptr == NULL ) return;
755
756 // get target block
757 FREE_BLOCK *target = BLOCK_ADRS(ptr);
758
759 // check next block, merge?
760 FREE_BLOCK *next = PHYS_NEXT(target);
761
762 if( IS_FREE_BLOCK(next) ) {
763 remove_free_block( pool, next );
764 merge_block(target, next);
765 } else {
766 SET_PREV_FREE(next);
767 }
768
769 // check prev block, merge?
770 if( IS_PREV_FREE(target) ) {
771 FREE_BLOCK *prev = *((FREE_BLOCK **)((uint8_t*)target - sizeof(FREE_BLOCK *)));
772
773 assert( IS_FREE_BLOCK(prev) );
774 remove_free_block( pool, prev );
775 merge_block(prev, target);
776 target = prev;
777 }
778
779 // target, add to index
780 add_free_block( pool, target );
781
782#if defined(MRBC_USE_ALLOC_PROF)
783 alloc_profile();
784#endif
785}
786
787
788//================================================================
796void * mrbc_raw_realloc(void *ptr, unsigned int size)
797{
798 if (ptr != NULL && size == 0) {
799 mrbc_raw_free(ptr);
800 return NULL;
801 }
802
803 MEMORY_POOL *pool = memory_pool;
804 volatile USED_BLOCK *target = BLOCK_ADRS(ptr);
805 MRBC_ALLOC_MEMSIZE_T alloc_size = size + sizeof(USED_BLOCK);
806 FREE_BLOCK *next;
807
808 // align 4 byte
809 alloc_size += (-alloc_size & 3);
810
811 // check minimum alloc size.
812 if( alloc_size < MRBC_MIN_MEMORY_BLOCK_SIZE ) alloc_size = MRBC_MIN_MEMORY_BLOCK_SIZE;
813
814 // expand? part1.
815 // next phys block is free and enough size?
816 if( alloc_size > BLOCK_SIZE(target) ) {
817 next = PHYS_NEXT(target);
818 if( IS_USED_BLOCK(next) ) goto ALLOC_AND_COPY;
819 if( (BLOCK_SIZE(target) + BLOCK_SIZE(next)) < alloc_size ) goto ALLOC_AND_COPY;
820
821 remove_free_block( pool, next );
822 merge_block((FREE_BLOCK *)target, next);
823 }
824 next = PHYS_NEXT(target);
825
826 // try shrink.
827 FREE_BLOCK *release = split_block((FREE_BLOCK *)target, alloc_size);
828 if( release != NULL ) {
829 SET_PREV_USED(release);
830 } else {
831 SET_PREV_USED(next);
832#if defined(MRBC_USE_ALLOC_PROF)
833 alloc_profile();
834#endif
835 return ptr;
836 }
837
838 // check next block, merge?
839 if( IS_FREE_BLOCK(next) ) {
840 remove_free_block( pool, next );
841 merge_block(release, next);
842 } else {
843 SET_PREV_FREE(next);
844 }
845 add_free_block( pool, release );
846#if defined(MRBC_USE_ALLOC_PROF)
847 alloc_profile();
848#endif
849 return ptr;
850
851
852 // expand part2.
853 // new alloc and copy
854 ALLOC_AND_COPY: {
855 void *new_ptr = mrbc_raw_alloc(size);
856 if( new_ptr == NULL ) return NULL; // ENOMEM
857
858 memcpy(new_ptr, ptr, BLOCK_SIZE(target) - sizeof(USED_BLOCK));
859 mrbc_set_vm_id(new_ptr, target->vm_id);
860
861 mrbc_raw_free(ptr);
862
863 return new_ptr;
864 }
865}
866
867
868//================================================================
874unsigned int mrbc_alloc_usable_size(void *ptr)
875{
876 USED_BLOCK *target = BLOCK_ADRS(ptr);
877 return (unsigned int)(BLOCK_SIZE(target) - sizeof(USED_BLOCK));
878}
879
880
881#if defined(MRBC_ALLOC_VMID)
882//================================================================
890void * mrbc_alloc(const struct VM *vm, unsigned int size)
891{
892 void *ptr = mrbc_raw_alloc(size);
893 if( ptr == NULL ) return NULL; // ENOMEM
894
895 if( vm ) mrbc_set_vm_id(ptr, vm->vm_id);
896
897 return ptr;
898}
899
900
901//================================================================
910void * mrbc_calloc(const struct VM *vm, unsigned int nmemb, unsigned int size)
911{
912 void *ptr = mrbc_raw_calloc(nmemb, size);
913 if( ptr == NULL ) return NULL; // ENOMEM
914
915 if( vm ) mrbc_set_vm_id(ptr, vm->vm_id);
916
917 return ptr;
918}
919
920
921//================================================================
926void mrbc_free_all(const struct VM *vm)
927{
928 MEMORY_POOL *pool = memory_pool;
929 USED_BLOCK *target = BPOOL_TOP(pool);
930 USED_BLOCK *next;
931 int vm_id = vm->vm_id;
932
933 while( target < (USED_BLOCK *)BPOOL_END(pool) ) {
934 next = PHYS_NEXT(target);
935 if( IS_FREE_BLOCK(next) ) next = PHYS_NEXT(next);
936
937 if( IS_USED_BLOCK(target) && (target->vm_id == vm_id) ) {
938 mrbc_raw_free( (uint8_t *)target + sizeof(USED_BLOCK) );
939 }
940 target = next;
941 }
942}
943
944
945//================================================================
951void mrbc_set_vm_id(void *ptr, int vm_id)
952{
953 SET_VM_ID( BLOCK_ADRS(ptr), vm_id );
954}
955
956
957//================================================================
963int mrbc_get_vm_id(void *ptr)
964{
965 return GET_VM_ID( BLOCK_ADRS(ptr) );
966}
967#endif // defined(MRBC_ALLOC_VMID)
968
969
970//================================================================
976{
977 MEMORY_POOL *pool = memory_pool;
978 USED_BLOCK *block = BPOOL_TOP(pool);
979 int flag_used_free = IS_USED_BLOCK(block);
980
981 ret->total = pool->size;
982 ret->used = 0;
983 ret->free = 0;
984 ret->fragmentation = -1;
985
986 while( block < (USED_BLOCK *)BPOOL_END(pool) ) {
987 if( IS_FREE_BLOCK(block) ) {
988 ret->free += BLOCK_SIZE(block);
989 } else {
990 ret->used += BLOCK_SIZE(block);
991 }
992 if( flag_used_free != IS_USED_BLOCK(block) ) {
993 ret->fragmentation++;
994 flag_used_free = IS_USED_BLOCK(block);
995 }
996 block = PHYS_NEXT(block);
997 }
998}
999
1000
1001#if defined(MRBC_USE_ALLOC_PROF)
1002//================================================================
1005void mrbc_alloc_start_profiling(void)
1006{
1007 if (profiling) return;
1008 profiling = 1;
1009 alloc_prof.max = 0;
1010 alloc_profile();
1011 alloc_prof.initial = alloc_prof.min = alloc_prof.max;
1012}
1013
1014//================================================================
1017void mrbc_alloc_stop_profiling(void)
1018{
1019 if (!profiling) return;
1020 profiling = 0;
1021}
1022
1023//================================================================
1028void mrbc_alloc_get_profiling(struct MRBC_ALLOC_PROF *prof)
1029{
1030 memcpy(prof, &alloc_prof, sizeof(struct MRBC_ALLOC_PROF));
1031}
1032#endif // defined(MRBC_USE_ALLOC_PROF)
1033
1034
1035#if defined(MRBC_DEBUG)
1036//================================================================
1042void mrbc_alloc_print_statistics( void )
1043{
1044 struct MRBC_ALLOC_STATISTICS stat;
1045 mrbc_alloc_statistics( &stat );
1046 mrbc_printf("== MEMORY STAT ==\n");
1047 mrbc_printf(" total:%d used:%d free:%d frag:%d\n",
1048 stat.total, stat.used, stat.free, stat.fragmentation );
1049}
1050
1051
1052//================================================================
1058void mrbc_alloc_print_pool_header( void *pool_header )
1059{
1060 MEMORY_POOL *pool = pool_header ? pool_header : memory_pool;
1061
1062 mrbc_printf("== MEMORY POOL HEADER DUMP ==\n");
1063 mrbc_printf(" Address:%p - %p - %p ", pool,
1064 BPOOL_TOP(pool), BPOOL_END(pool));
1065 mrbc_printf(" Size Total:%d User:%d\n",
1066 pool->size, pool->size - sizeof(MEMORY_POOL));
1067 mrbc_printf(" sizeof MEMORY_POOL:%d(%04x), USED_BLOCK:%d(%02x), FREE_BLOCK:%d(%02x)\n",
1068 sizeof(MEMORY_POOL), sizeof(MEMORY_POOL),
1069 sizeof(USED_BLOCK), sizeof(USED_BLOCK),
1070 sizeof(FREE_BLOCK), sizeof(FREE_BLOCK) );
1071
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("-"); }
1075 mrbc_printf("\n");
1076 for( int i = 0; i < sizeof(pool->free_sli_bitmap); i++ ) {
1077 mrbc_printf(" [%2d] %d : ", i, !!((pool->free_fli_bitmap << i) & MSB_BIT1_FLI));
1078 for( int j = 0; j < 8; j++ ) {
1079 mrbc_printf("%d", !!((pool->free_sli_bitmap[i] << j) & MSB_BIT1_SLI));
1080 if( (j % 4) == 3 ) mrbc_printf(" ");
1081 }
1082
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;
1086 mrbc_printf(" %p", pool->free_blocks[idx] );
1087 }
1088 mrbc_printf( "\n" );
1089 }
1090}
1091
1092void mrbc_alloc_print_memory_block( void *pool_header )
1093{
1094 const int DUMP_BYTES = 32;
1095 MEMORY_POOL *pool = pool_header ? pool_header : memory_pool;
1096
1097 mrbc_printf("== MEMORY BLOCK DUMP ==\n");
1098 FREE_BLOCK *block = BPOOL_TOP(pool);
1099
1100 while( block < (FREE_BLOCK *)BPOOL_END(pool) ) {
1101 mrbc_printf("%p", block );
1102#if defined(MRBC_ALLOC_VMID)
1103 mrbc_printf(" id:%02x", block->vm_id );
1104#endif
1105 mrbc_printf(" size:%5d($%04x) use:%d prv:%d ",
1106 block->size & ~0x03, block->size & ~0x03,
1107 !!(block->size & 0x01), !!(block->size & 0x02) );
1108
1109 if( IS_USED_BLOCK(block) ) {
1110 /* Used block */
1111 int n = DUMP_BYTES;
1112 if( n > (BLOCK_SIZE(block) - sizeof(USED_BLOCK)) ) {
1113 n = BLOCK_SIZE(block) - sizeof(USED_BLOCK);
1114 }
1115 uint8_t *p = (uint8_t *)block + sizeof(USED_BLOCK);
1116 int i;
1117 for( i = 0; i < n; i++) mrbc_printf(" %02x", *p++ );
1118 for( ; i < DUMP_BYTES; i++ ) mrbc_printf(" ");
1119
1120 mrbc_printf(" ");
1121 p = (uint8_t *)block + sizeof(USED_BLOCK);
1122 for( i = 0; i < n; i++) {
1123 int ch = *p++;
1124 mrbc_printf("%c", (' ' <= ch && ch < 0x7f)? ch : '.');
1125 }
1126
1127 } else {
1128 /* Free block */
1129 unsigned int index = calc_index(BLOCK_SIZE(block));
1130 mrbc_printf(" fli:%d sli:%d pf:%p nf:%p",
1131 FLI(index), SLI(index), block->prev_free, block->next_free);
1132 }
1133
1134 mrbc_printf("\n");
1135 block = PHYS_NEXT(block);
1136 }
1137}
1138
1139void mrbc_alloc_print_memory_pool( void )
1140{
1141 mrbc_alloc_print_pool_header(0);
1142 mrbc_alloc_print_memory_block(0);
1143}
1144
1145#endif // defined(MRBC_DEBUG)
1146#endif // !defined(MRBC_ALLOC_LIBC)
#define NLZ_SLI(x)
Definition alloc.c:224
static unsigned int calc_index(MRBC_ALLOC_MEMSIZE_T alloc_size)
Definition alloc.c:281
void * mrbc_raw_alloc(unsigned int size)
Definition alloc.c:500
static FREE_BLOCK * split_block(FREE_BLOCK *target, MRBC_ALLOC_MEMSIZE_T size)
Definition alloc.c:400
#define BLOCK_ADRS(p)
Definition alloc.c:219
#define SIZE_FREE_BLOCKS
Definition alloc.c:89
#define FLI(x)
Definition alloc.c:103
void mrbc_alloc_statistics(struct MRBC_ALLOC_STATISTICS *ret)
Definition alloc.c:975
#define SET_PREV_FREE(p)
Definition alloc.c:187
#define MRBC_ALLOC_FLI_BIT_WIDTH
Definition alloc.c:80
#define SET_VM_ID(p, id)
Definition alloc.c:196
#define BPOOL_TOP(memory_pool)
Definition alloc.c:217
#define IS_FREE_BLOCK(p)
Definition alloc.c:185
static int nlz8(uint8_t x)
Definition alloc.c:264
#define GET_VM_ID(p)
Definition alloc.c:197
static void merge_block(FREE_BLOCK *target, FREE_BLOCK *next)
Definition alloc.c:422
#define BLOCK_SIZE(p)
Definition alloc.c:180
void * mrbc_raw_alloc_no_free(unsigned int size)
Definition alloc.c:619
#define IS_USED_BLOCK(p)
Definition alloc.c:184
static void remove_free_block(MEMORY_POOL *pool, FREE_BLOCK *target)
Definition alloc.c:344
#define SET_FREE_BLOCK(p)
Definition alloc.c:183
#define MRBC_MIN_MEMORY_BLOCK_SIZE
Definition alloc.c:97
#define MRBC_ALLOC_IGNORE_LSBS
Definition alloc.c:86
#define PHYS_NEXT(p)
Definition alloc.c:181
void * mrbc_raw_realloc(void *ptr, unsigned int size)
Definition alloc.c:796
#define BPOOL_END(memory_pool)
Definition alloc.c:218
void mrbc_init_alloc(void *ptr, unsigned int size)
Definition alloc.c:438
static int nlz16(uint16_t x)
Definition alloc.c:246
#define SET_PREV_USED(p)
Definition alloc.c:186
#define SET_USED_BLOCK(p)
Definition alloc.c:182
unsigned int mrbc_alloc_usable_size(void *ptr)
Definition alloc.c:874
#define MSB_BIT1_SLI
Definition alloc.c:222
#define MRBC_ALLOC_SLI_BIT_WIDTH
Definition alloc.c:83
static void add_free_block(MEMORY_POOL *pool, FREE_BLOCK *target)
Definition alloc.c:314
#define IS_PREV_FREE(p)
Definition alloc.c:189
void * mrbc_raw_calloc(unsigned int nmemb, unsigned int size)
Definition alloc.c:674
static MEMORY_POOL * memory_pool
Definition alloc.c:230
#define MSB_BIT1_FLI
Definition alloc.c:221
void mrbc_raw_free(void *ptr)
Definition alloc.c:695
void mrbc_cleanup_alloc(void)
Definition alloc.c:481
#define SLI(x)
Definition alloc.c:104
#define NLZ_FLI(x)
Definition alloc.c:223
mruby/c memory management.
static mrbc_int_t shift(mrbc_int_t x, mrbc_int_t y)
Definition c_numeric.c:163
void mrbc_printf(const char *fstr,...)
Definition console.c:180
console output module. (not yet input)
uint8_t pad[3]
Definition alloc.c:211
FREE_BLOCK * free_blocks[SIZE_FREE_BLOCKS+1]
Definition alloc.c:214
MRBC_ALLOC_MEMSIZE_T size
Definition alloc.c:205
uint8_t free_sli_bitmap[MRBC_ALLOC_FLI_BIT_WIDTH+1+1]
Definition alloc.c:209
uint16_t free_fli_bitmap
Definition alloc.c:208
for memory allocation profiling functions. if you use this, define MRBC_USE_ALLOC_PROF pre-processor ...
Definition alloc.h:49
unsigned long max
Definition alloc.h:51
unsigned long min
Definition alloc.h:52
unsigned long initial
Definition alloc.h:50
Return value structure for mrbc_alloc_statistics function.
Definition alloc.h:38
unsigned int total
returns total memory.
Definition alloc.h:39
unsigned int used
returns used memory.
Definition alloc.h:40
unsigned int fragmentation
returns memory fragmentation count.
Definition alloc.h:42
unsigned int free
returns free memory.
Definition alloc.h:41
Virtual Machine.
Definition vm.h:140
uint8_t vm_id
vm_id : 1..MAX_VM_COUNT
Definition vm.h:144
Global configuration of mruby/c VM's.