#ifdef HAVE_CONFIG_H #include #endif #define INIT_ON_FLIP //#define GC_PRINT_DEBUG_ALIGN //#define GC_PRINT_DEBUG_EVACUATE #define DO_ALIGN #define ALIGNMENT 4 #ifdef GC_PRINT_WARNINGS #if !(defined HOST_AVR || defined HOST_RTAI_KERNEL) #include #endif #endif #include "gc.h" #include "gc_types.h" #include "gci_common.h" #include "gc_roots.h" #include "gc_batch_copy.h" void *gc_heap_base; #if GC_THREAD == GC_THREAD_STORK || GC_THREAD == GC_THREAD_RTAIKERNEL uint8 gc_heap[GC_HEAPSIZE]; #endif static void *tospace, *fromspace, *allocpos; ObjectHead *scanp; void gc_evacuate(GC___REF(ObjectHead) *o); static unsigned int semi_size; #ifdef DO_ALIGN static unsigned int roundup( unsigned int size ) { unsigned int newsize = (size + ALIGNMENT - 1) & -ALIGNMENT; #ifdef GC_PRINT_DEBUG_ALIGN if(newsize != size) printf("roundup: %d -> %d\n", size, newsize); #endif return newsize; } #endif int gc_init(int heapsize){ int result = gc_create_heap(heapsize); if(result) { tospace=(void *) gc_heap_base; // HERE BE DRAGONS!!! // the border between tospace and fromspace should be // (at least) 64 bits aligned... semi_size = heapsize / 2; fromspace=(void *) (((unsigned int) gc_heap_base)+semi_size); allocpos=tospace; gc_roots_gc_init(&gc_evacuate); } return result; } void *gc_new(uint32 size,void *tmplate) { void *result; #ifdef DO_ALIGN size = roundup(size); #endif if( !(semi_size - (allocpos - tospace) >= size ) ) { gc(); } if( (semi_size - (allocpos - tospace) >= size ) ) { result = allocpos; GC___CPTR(ObjectHead,result)->tmplate = tmplate; allocpos += size; } else { #ifdef GC_PRINT_WARNINGS printf("gc_batch_copy.c: out of memory when allocating object\n"); #endif #if HAS_EXCEPTIONS == 0 && !defined HOST_RTAI_KERNEL exit(1); #endif result = 0; } #ifndef INIT_ON_FLIP memset(result,0,size); #endif return result; } int gc_create_heap(unsigned int size) { #if GC_THREAD == GC_THREAD_STORK || GC_THREAD == GC_THREAD_RTAIKERNEL #ifdef INIT_ON_FLIP memset(gc_heap, 0, GC_HEAPSIZE); #endif gc_heap_base = &gc_heap; if( 1 ) { #else #ifdef INIT_ON_FLIP #if defined HOST_AVR if(gc_heap_base = (void *) myMalloc(size)) { #elif defined HOST_RTAI_KERNEL gc_heap_base = &gc_heap; #else if(gc_heap_base = (void *) malloc(size)) { #endif memset(gc_heap_base, 0, size); // calloc initialises the memory to zero... #else if(gc_heap_base = (void *) malloc(size)) { #endif #endif #ifdef GC_PRINT_DEBUG printf("gc_create_heap: heap_base = %p\n", gc_heap_base); #endif return 1; } else { return 0; } } void gc_cycle_init(void) { void *tmp; /* flip */ #ifdef GC_PRINT_DEBUG printf("gc_batch_copy.c: flip!\n"); #endif tmp = fromspace; fromspace = tospace; tospace = tmp; allocpos = tospace; #ifdef INIT_ON_FLIP memset(tospace, 0, semi_size); #endif gc_roots_initiate_gc_cycle(); scanp = tospace; } int inFromspace(void *o) { return o >= fromspace && o < (fromspace + semi_size); } void gc_evacuate(GC___REF(ObjectHead) *o) { GC___REF(ObjectHead) obj = *o; #ifdef GC_PRINT_DEBUG_EVACUATE printf("evacuate %p\n",o); #endif if( inFromspace(GC___PTR(obj) ) ){ #ifdef GC_PRINT_DEBUG_EVACUATE printf(" in fromspace\n",o); #endif if( GC___PTR(obj)->gc.fp == 0 ) { #ifdef GC_PRINT_DEBUG_EVACUATE printf(" evacuating\n",o); #endif // evacuate int osize = getsize( GC___PTR(obj)); #ifdef DO_ALIGN osize = roundup(osize); #endif #ifdef GC_PRINT_DEBUG_EVACUATE printf(" size = %d, allocpos = %p\n",osize,allocpos); #endif memcpy(allocpos, GC___PTR(obj), osize); GC___PTR(obj)->gc.fp = allocpos; allocpos += osize; #ifdef GC_PRINT_DEBUG_EVACUATE printf(" done\n",o); #endif } *o = GC___PTR(obj)->gc.fp; } // else already evacuated... #ifdef GC_PRINT_DEBUG_EVACUATE printf("end\n",o); #endif } void gc(void) { gc_cycle_init(); while(gc_roots_mark_one()); while(scanp < allocpos) { int osize; osize = getsize(scanp); #ifdef DO_ALIGN osize = roundup(osize); #endif gc_parse_object(scanp, gc_evacuate); scanp = (ObjectHead *) (void *) (((uint8 *) scanp)+osize); } } void gc_full_cycle(void) { gc(); } void gc_finalize_all(void) { printf("gc_finalize_all() not implemented in batch-copy\n"); }