//#define DEBUG #include #include "debug.h" #include "mem.h" /* CPU REGISTERS */ OBJ r0=0, r1=0, r2=0, r3=0, r4=0, r5=0, r6=0, r7=0, r8=0, r9=0, ra=0, rb=0, rc=0, rd=0, re=0, rf=0, stack=0; OBJ *sp=0; /* HEAP STRUCTURE */ struct { void *start; /* HEAP */ void *next; /* NEXT AVAILABLE HEAP POSITION */ void *last; /* LAST AVAILABLE POSITION (EXCLUSIVE) */ U32 dirtycount; /* NUMBER OF DIRTY TYPES CURRENTLY IN HEAP */ U32 gccount; /* GARBAGE COLLECTION COUNT */ } old, heap, newheap; /* THIS MUST BE CALLED BEFORE USAGE OF THIS LIBRARY */ void mem_init (void) { DB("MEM_INIT"); (heap.start = (OBJ)calloc(INCREMENT_HEAP_SIZE, 1)) || fprintf (stderr, "WARNING: heap_init(): can't create inital heap\n"); heap.next = heap.start; heap.last = heap.start + INCREMENT_HEAP_SIZE; /* EXCLUSIVE */ heap.dirtycount=0; DB("mem_init"); } /* FUN HEAP STATISTICS. */ U32 mem_heap_size (void) { return (U32)heap.last-(U32)heap.start; } U32 mem_heap_count (void) { return (U32)heap.next-(U32)heap.start; } U32 mem_heap_free (void) { return (U32)heap.last-(U32)heap.next; } U32 mem_heap_gccount(void) { return heap.gccount; } void mem_heap_inc_dirtycount(void) { heap.dirtycount++; } U32 is_obj_in_old (OBJ o){ return o >= old.start && o < old.last; } U32 is_obj_in_heap (OBJ o){ return o >= heap.start && o < heap.last; } U32 is_obj_in_newheap (OBJ o){ return o >= newheap.start && o < newheap.last; } /* OBJECT SELECTORS */ desc_t* desc_ref (OBJ o) { return o-DESC_SIZE; } void obj_type_set (OBJ o, U8 t) {*(U8*)(o-1)=t;}/* LITTLE ENDIAN */ U8 inline obj_type (OBJ o) { return *(U8*)(o-1); } /* LITTLE ENDIAN */ U32 obj_len (OBJ o) { return *desc_ref(o) & DESC_LENGTH_MASK; } U8 obj_class (OBJ o) { return obj_type(o) & TYPE_CLASS_MASK; } U8 obj_id (OBJ o) { return obj_type(o) & TYPE_ID_MASK; } U32 obj_is_defined (OBJ o) { return (U32)o; } /* ALL OBJ ARE INITIALLY NULL */ U32 obj_is_ary (OBJ o) { return obj_class(o) == ARRAY_CLASS; } U32 obj_is_drt (OBJ o) { return obj_class(o) == DIRTY_CLASS; } U32 obj_is_vec (OBJ o) { return obj_class(o) == VECTOR_CLASS; } U32 obj_is_stk (OBJ o) { return obj_class(o) == STACK_CLASS; } U32 obj_is_shadow (OBJ o) { return obj_type(o) == SHADOW_TYPE; } U32 obj_is_static (OBJ o) { return !is_obj_in_heap(o);} U32 obj_size (OBJ o) { return DESC_SIZE + ((obj_is_ary(o)||obj_is_drt(o)) ? ary_to_size(obj_len(o)) : vec_to_size(obj_len(o))); } U32 mem_stk_count (OBJ o) {return stack==o?sp-(OBJ*)stack:*(U32*)o; } /* RETURNS THE ADDRESS OF AN ARRAY/VECTOR ELEMENT. */ U8* mem_ary_ref (OBJ o, U32 r) { return (U8*)o + r; } void* mem_drt_clnr(OBJ o) { return o; } void* mem_drt_ref (OBJ o, U32 r) { return o + sizeof(void*) + r; } OBJ* mem_vec_ref (OBJ o, U32 r) { return (OBJ*)o + r; } OBJ* mem_stk_ref (OBJ o, U32 r) { return (OBJ*)o + mem_stk_count(o) - r; } /* RETURNS ELEMENT OF THE ARRAY/VECTOR. */ U8 mem_ary_obj (OBJ o, U32 r) { return *mem_ary_ref(o, r); } OBJ mem_vec_obj (OBJ o, U32 r) { return *mem_vec_ref(o, r); } OBJ mem_stk_obj (OBJ o, U32 r) { return *mem_stk_ref(o, r); } OBJ shadow_obj (OBJ h) { return mem_vec_obj (h, 0); } /* MUTATE AN OBJECT ARRAY/VECTOR ENTRY. */ void mem_ary_set (OBJ o, U32 r, U8 p) { *mem_ary_ref(o, r)=p; } void mem_vec_set (OBJ o, U32 r, OBJ p) { *mem_vec_ref(o, r)=p; } void stack_push (OBJ o) { *(++sp) = o; } OBJ stack_pop (void) { return *(sp--); } OBJ stack_peek (U32 i) { return *(sp-i); } void shadow_set (OBJ o, OBJ p) { /* MUTATE AN OBJECT INTO A SHADOW */ *desc_ref(o) = MAKE_DESC(SHADOW_TYPE, ((obj_size(o)-DESC_SIZE)/sizeof(OBJ))); mem_vec_set(o, 0, p); /* OBJECT NOW A VECTOR POINTING TO NEW LOCATION */ } /* ALLOCATED AN OBJECT IN THE HEAP: * THE DESCRIPTOR PARAMATER IS A LONG [tsss] t=type-field s=size=field. * A TYPE >= 0X80 IS ASSUMED A VECTOR OF OBJECTS (POINTERS, LENGTH 4 ON INTEL * BOXEN). A TYPE < 0X80 IS RAW BYTES. THIS RESTRICTION IS USED BY THE GC. * * THE SIZE PARAMATER IS THE NUMBER OF ACTUAL BYTES THE OBJECT IS COMPOSED * OF PLUS THE DESCRIPTOR SIZE. IT SHOULD BE AT LEAST 4 TO ALLOW FOR MUTATION * INTO A SHADOW BY THE GC. */ void mem_obj_new (desc_t desc, U32 size) { *(desc_t*)heap.next = desc; r0 = heap.next += DESC_SIZE; /* SAVE OBJ ADDR TO R0*/ heap.next += size; /* COMPUTE OBJECT SIZE */ if (heap.next >= heap.last) { /* WAS IT WAS UNSUCCESSFULL */ BRED;DB("UNSUCCESSFULL"); r0 = 0; heap.next -= (size + DESC_SIZE); mem_gc(size+DESC_SIZE); /* GC IF IT WASN'T AND CALL SELF AGAIN */ mem_obj_new(desc, size); } } /* DYNAMICALLY ALLOCATE THIS OBJECT...IT WILL BE SKIPPED BY THE GC SINCE IT WONT BE IN THE CURRENT HEAP. */ void mem_obj_new_static (desc_t desc, U32 length) { r0 = (OBJ)calloc(DESC_SIZE+length, 1); *(desc_t*)r0 = desc; r0 += DESC_SIZE; } /* SWAP ACC AND STACK REGISTERS. THIS FORCES A CORRECT STACK OBJECT (SINCE WE * USUALLY JUST MUTATE THE STACK POINTER AND NOT THE STACK OBJECTS COUNT VALUE) */ void mem_swap_stack (void) { OBJ t; if (sp) *(U32*)stack = (sp-(OBJ*)stack); /* SYNC STACK OBJECT WITH SP */ t=r0; r0 = stack; stack = t; if (obj_is_stk(stack)) sp = (OBJ*)stack + *(U32*)stack; /* SYNC SP WITH STACK OBJECT */ else sp=0; } /* GIVEN POINTER TO AN OBJECT, MOVE OBJECT INTO OTHER HEAP. */ void heap_obj_copy (OBJ *o) { int len, stk_count; OBJ newloc; BRED;DB("HEAP_OBJ_COPY"); if (!*o) return; /* IF UNDEFINED DO NOTHING */ if (obj_is_static(*o)) { return; } /* IS OBJECT IN HEAP? */ if (obj_is_shadow(*o)) { /* IF SHADOW, UPDATE OBJ TO EXISTING NEW LOCATION */ *o = (OBJ)shadow_obj(*o); return; } len = obj_size(*o); /* OBJ LEN IN BYTES INCLUDING DESCRIPTOR */ if (obj_is_stk(*o)) { /* COPY STACK ELEMENTS */ stk_count = mem_stk_count(*o); memcpy(newheap.next, *o-DESC_SIZE, DESC_SIZE+sizeof(OBJ)+stk_count*sizeof(OBJ)); } else { /* COPY OBJ */ memcpy(newheap.next, *o-DESC_SIZE, len); if (obj_is_drt(*o)) newheap.dirtycount++; /* TALLY COPIED DIRTY OBJS */ } shadow_set(*o, newloc=newheap.next+DESC_SIZE); /* SHADOW OLD OBJ TO NEW */ newheap.next += len; /* INC NEW HEAP NEXT POINTER */ *o = newloc; /* SET OBJ TO NEW LOCATION */ } /* FORCE GARBAGE COLLECTION. */ void mem_gc (U32 DESIRED) { U32 i, len; void *newnext; long NEW_HEAP_SIZE; OBJ *o; BRED;DB("GC-----------------------------------------"); //mem_stats_dump(); heap.gccount++; NEW_HEAP_SIZE = mem_heap_size() + INCREMENT_HEAP_SIZE + DESIRED; (newheap.next = newheap.start = (OBJ)calloc(NEW_HEAP_SIZE,1)) || fprintf (stderr, "WARNING: can't create newheap\n"); newheap.last = newheap.start + NEW_HEAP_SIZE; newheap.dirtycount = 0; /* COPY AND MUTATE REGISTERS AND STACK */ heap_obj_copy(&r0);heap_obj_copy(&r1);heap_obj_copy(&r2);heap_obj_copy(&r3); heap_obj_copy(&r4);heap_obj_copy(&r5);heap_obj_copy(&r6);heap_obj_copy(&r7); heap_obj_copy(&r8);heap_obj_copy(&r9);heap_obj_copy(&ra);heap_obj_copy(&rb); heap_obj_copy(&rc);heap_obj_copy(&rd);heap_obj_copy(&re);heap_obj_copy(&rf); len = mem_stk_count(stack); heap_obj_copy(&stack); sp = (OBJ*)stack + len; /* SYNC SP WITH STACK OBJECT */ /* COMPACT BASED ON ALREADY COMPACTED HEAD OBJECTS */ newnext = newheap.start + DESC_SIZE; while (newnext < newheap.next) { if (obj_is_vec(newnext)) { len = obj_len(newnext); for (i=0; i 0xffff) heap_obj_copy(o); // ...DATA IF VALUE < 0x10000 } } else if (obj_is_stk(newnext)) { len = mem_stk_count(newnext); for (i=0; i INCREMENT_HEAP_SIZE*2 + DESIRED) { newnext = heap.start; /* CHECK TO MAKE SURE THE HEAP DIDN'T MOVE */ heap.start = (void*)realloc(heap.start,NEW_HEAP_SIZE-(INCREMENT_HEAP_SIZE+DECREMENT_HEAP_SIZE+DESIRED)); (heap.start == newnext) || fprintf (stderr, "WARNING: heap reloacted after realloc!!!"); heap.last -= INCREMENT_HEAP_SIZE+DECREMENT_HEAP_SIZE+DESIRED; } //mem_stats_dump(); BRED;DB("-------------------GC\n"); } /* DEVELOPMENT DEBUGGING AIDS. */ void mem_heap_info (void) { printf ("\n---------------------------------------------------------"); printf ("\nHeap%8x Size %8x\nNext%8x Count%8x\nLast%8x Free %8x", heap.start, mem_heap_size(), heap.next, mem_heap_count(), heap.last, mem_heap_free()); } void mem_stats_dump (void) { U32 i; OBJ obj; mem_heap_info(); printf ("\n -0- -1- -2- -3- -4- -5- -6- -7-"); printf ("\n%08x %08x %08x %08x %08x %08x %08x %08x",r0, r1, r2, r3, r4, r5, r6, r7); printf ("\n%08x %08x %08x %08x %08x %08x %08x %08x %08x",r8, r9, ra, rb, rc, rd, re, rf, stack); printf ("\n -8- -9- -a- -b- -c- -d- -e- -f- -stack-", stack); /* DUMP EACH HEAP OBJECT */ for (obj = heap.start+DESC_SIZE; obj", o, obj_len(o), shadow_obj(o)); else if (obj_is_vec(o)) { printf ("%x %02x %lx < ", o, obj_type(o), obj_len(o)); for (i=0; i"); } else if (obj_is_ary(o)) { printf ("%x %02x %lx ( ", o, obj_type(o), obj_len(o)); for (i=0; i0; i--) printf ("%x ", mem_stk_obj(o, i-1)); } else if (obj_is_drt(o)) { printf ("%x %02x %lx { %x ", o, obj_type(o), obj_len(o), *(U32*)mem_drt_clnr(o)); for (i=0; i"); } else if (obj_is_ary(o)) { putchar ('"'); for (i=0; i