3 #include "structdefs.h"
5 #include "SimpleHash.h"
7 #include "GenericHashtable.h"
9 #if defined(THREADS) || defined(DSTM) || defined(STM)
18 #include <DSTM/interface_recovery/dstm.h>
20 #include <DSTM/interface/dstm.h>
27 #include "delaycomp.h"
33 #define INITIALHEAPSIZE 256*1024*1024L
34 #define GCPOINT(x) ((INTPTR)((x)*0.99))
35 /* This define takes in how full the heap is initially and returns a new heap size to use */
36 #define HEAPSIZE(x,y) ((INTPTR)(x+y))*2
39 extern struct genhashtable * activetasks;
41 extern struct parameterwrapper * objectqueues[NUMCLASSES];
43 extern struct genhashtable * failedtasks;
44 extern struct taskparamdescriptor *currtpd;
45 extern struct ctable *forward;
46 extern struct ctable *reverse;
47 extern struct RuntimeHash *fdtoobject;
52 long garbagearray[MAXSTATS];
55 #if defined(THREADS) || defined(DSTM) || defined(STM)
57 struct listitem * list=NULL;
60 __thread struct listitem litem;
64 //Need to check if pointers are transaction pointers
65 //this also catches the special flag value of 1 for local copies
67 #define ENQUEUE(orig, dst) \
68 if ((!(((unsigned int)orig)&0x1))) { \
69 if (orig>=curr_heapbase&&orig<curr_heaptop) { \
71 if (gc_createcopy(orig,©)) \
77 #define ENQUEUE(orig, dst) \
78 if (orig>=curr_heapbase&&orig<curr_heaptop) { \
80 if (gc_createcopy(orig,©)) \
84 #define SENQUEUE(orig, dst) \
87 if (gc_createcopy(orig,©)) \
91 #elif defined(FASTCHECK)
92 #define ENQUEUE(orig, dst) \
93 if (((unsigned int)orig)!=1) { \
95 if (gc_createcopy(orig,©)) \
99 #define ENQUEUE(orig, dst) \
101 if (gc_createcopy(orig,©)) \
106 struct pointerblock {
107 void * ptrs[NUMPTRS];
108 struct pointerblock *next;
111 void * curr_heapbase=0;
112 void * curr_heapptr=0;
113 void * curr_heapgcpoint=0;
114 void * curr_heaptop=0;
116 void * to_heapbase=0;
121 struct pointerblock *head=NULL;
123 struct pointerblock *tail=NULL;
125 struct pointerblock *spare=NULL;
127 void enqueue(void *ptr) {
128 if (headindex==NUMPTRS) {
129 struct pointerblock * tmp;
134 tmp=malloc(sizeof(struct pointerblock));
139 head->ptrs[headindex++]=ptr;
143 if (tailindex==NUMPTRS) {
144 struct pointerblock *tmp=tail;
152 return tail->ptrs[tailindex++];
156 void fixobjlist(struct objlist * ptr) {
159 for(i=0;i<ptr->offset;i++) {
160 SENQUEUE(ptr->objs[i], ptr->objs[i]);
166 void fixtable(chashlistnode_t ** tc_table, chashlistnode_t **tc_list, cliststruct_t **cstr, unsigned int tc_size) {
167 unsigned int mask=(tc_size<<4)-1;
168 chashlistnode_t *node=calloc(tc_size, sizeof(chashlistnode_t));
169 chashlistnode_t *ptr=*tc_table;
170 chashlistnode_t *curr;
174 chashlistnode_t *newlist=NULL;
175 for(i=0;i<tc_size;i++) {
178 do { //Inner loop to go through linked lists
180 chashlistnode_t *tmp,*next;
182 if ((key=(void *)curr->key) == 0) { //Exit inner loop if there the first element is 0
183 break; //key = val =0 for element if not present within the hash table
186 if (curr->val>=curr_heapbase&&curr->val<curr_heaptop) {
187 SENQUEUE(curr->val, curr->val);
189 //rewrite transaction cache entry
190 void *vptr=curr->val;
191 int type=((int *)vptr)[0];
192 unsigned INTPTR *pointer=pointerarray[type];
194 //array of primitives - do nothing
195 struct ArrayObject *ao=(struct ArrayObject *) vptr;
196 SENQUEUE((void *)ao->___objlocation___, *((void **)&ao->___objlocation___));
197 } else if (((INTPTR)pointer)==1) {
199 struct ArrayObject *ao=(struct ArrayObject *) vptr;
200 int length=ao->___length___;
202 SENQUEUE((void *)ao->___objlocation___, *((void **)&ao->___objlocation___));
204 int lowindex=ao->lowindex>>INDEXSHIFT;
205 int highind=ao->highindex;
206 int highindex=(highind==-1)?-1:(highind>>INDEXSHIFT);
208 for(j=lowindex; j<=highindex; j++) {
209 unsigned int lockval;
210 if (GETLOCKVAL(lockval, ao, j)==STMDIRY) {
211 int lowi=(j<<INDEXSHIFT)/sizeof(void *);
212 int highi=lowi+(INDEXLENGTH/sizeof(void *));
213 for(i=lowi; i<highi;i++) {
215 for(i=0; i<length; i++) {
217 void *objptr=((void **)(((char *)&ao->___length___)+sizeof(int)))[i];
218 SENQUEUE(objptr, ((void **)(((char *)&ao->___length___)+sizeof(int)))[i]);
224 INTPTR size=pointer[0];
226 for(i=1; i<=size; i++) {
227 unsigned int offset=pointer[i];
228 void * objptr=*((void **)(((char *)vptr)+offset));
229 SENQUEUE(objptr, *((void **)(((char *)vptr)+offset)));
235 index = (((unsigned INTPTR)key) & mask) >>4;
239 // Insert into the new table
241 tmp->key = curr->key;
242 tmp->val = curr->val;
245 } else if (isfirst) {
246 chashlistnode_t *newnode;
247 if ((*cstr)->num<NUMCLIST) {
248 newnode=&(*cstr)->array[(*cstr)->num];
252 cliststruct_t *tcl=calloc(1,sizeof(cliststruct_t));
255 newnode=&tcl->array[0];
258 newnode->key = curr->key;
259 newnode->val = curr->val;
260 newnode->next = tmp->next;
261 newnode->lnext=newlist;
267 curr->next=tmp->next;
281 if ((head==tail)&&(tailindex==headindex))
287 struct pointerblock *taghead=NULL;
290 void enqueuetag(struct ___TagDescriptor___ *ptr) {
291 if (tagindex==NUMPTRS) {
292 struct pointerblock * tmp=malloc(sizeof(struct pointerblock));
297 taghead->ptrs[tagindex++]=ptr;
301 #if defined(STM)||defined(THREADS)
302 __thread char * memorybase=NULL;
303 __thread char * memorytop=NULL;
307 void collect(struct garbagelist * stackptr) {
308 #if defined(THREADS)||defined(DSTM)||defined(STM)
310 pthread_mutex_lock(&gclistlock);
312 if ((listcount+1)==threadcount) {
313 break; /* Have all other threads stopped */
315 pthread_cond_wait(&gccond, &gclistlock);
319 ptrstack.prev=stackptr;
320 stackptr=(struct garbagelist *) &ptrstack;
322 arraystack.prev=stackptr;
323 stackptr=(struct garbagelist *) &arraystack;
330 for(i=0;i<MAXSTATS;i++)
338 head=tail=malloc(sizeof(struct pointerblock));
344 taghead=malloc(sizeof(struct pointerblock));
351 fixtable(&c_table, &c_list, &c_structs, c_size);
354 fixobjlist(lockedobjs);
360 /* Check current stack */
361 #if defined(THREADS)||defined(DSTM)||defined(STM)
363 struct listitem *listptr=list;
367 while(stackptr!=NULL) {
369 for(i=0; i<stackptr->size; i++) {
370 void * orig=stackptr->array[i];
371 ENQUEUE(orig, stackptr->array[i]);
373 stackptr=stackptr->next;
375 #if defined(THREADS)||defined(DSTM)||defined(STM)
376 /* Go to next thread */
379 if (listptr==&litem) {
380 listptr=listptr->next;
384 struct listitem *litem=pthread_getspecific(litemkey);
385 if (listptr==litem) {
386 listptr=listptr->next;
393 void * orig=listptr->locklist;
394 ENQUEUE(orig, listptr->locklist);
397 if ((*listptr->tc_table)!=NULL) {
398 fixtable(listptr->tc_table, listptr->tc_list, listptr->tc_structs, listptr->tc_size);
399 fixobjlist(listptr->objlist);
401 fixobjlist(listptr->lockedlist);
404 *(listptr->base)=NULL;
406 stackptr=listptr->stackptr;
407 listptr=listptr->next;
415 ENQUEUE(___fcrevert___, ___fcrevert___);
420 /* Update objectsets */
422 for(i=0; i<NUMCLASSES; i++) {
423 #if !defined(MULTICORE)
424 struct parameterwrapper * p=objectqueues[i];
426 struct ObjectHash * set=p->objectset;
427 struct ObjectNode * ptr=set->listhead;
429 void *orig=(void *)ptr->key;
430 ENQUEUE(orig, *((void **)(&ptr->key)));
433 ObjectHashrehash(set); /* Rehash the table */
442 struct cnode * ptr=forward->listhead;
444 void * orig=(void *)ptr->key;
445 ENQUEUE(orig, *((void **)(&ptr->key)));
448 crehash(forward); /* Rehash the table */
452 struct cnode * ptr=reverse->listhead;
454 void *orig=(void *)ptr->val;
455 ENQUEUE(orig, *((void**)(&ptr->val)));
462 struct RuntimeNode * ptr=fdtoobject->listhead;
464 void *orig=(void *)ptr->data;
465 ENQUEUE(orig, *((void**)(&ptr->data)));
471 /* Update current task descriptor */
473 for(i=0; i<currtpd->numParameters; i++) {
474 void *orig=currtpd->parameterArray[i];
475 ENQUEUE(orig, currtpd->parameterArray[i]);
480 /* Update active tasks */
482 struct genpointerlist * ptr=activetasks->list;
484 struct taskparamdescriptor *tpd=ptr->src;
486 for(i=0; i<tpd->numParameters; i++) {
487 void * orig=tpd->parameterArray[i];
488 ENQUEUE(orig, tpd->parameterArray[i]);
492 genrehash(activetasks);
495 /* Update failed tasks */
497 struct genpointerlist * ptr=failedtasks->list;
499 struct taskparamdescriptor *tpd=ptr->src;
501 for(i=0; i<tpd->numParameters; i++) {
502 void * orig=tpd->parameterArray[i];
503 ENQUEUE(orig, tpd->parameterArray[i]);
507 genrehash(failedtasks);
512 void * ptr=dequeue();
514 int type=((int *)cpy)[0];
515 unsigned INTPTR * pointer;
519 /* Nothing is inside */
524 pointer=pointerarray[type];
526 /* Array of primitives */
528 #if defined(DSTM)||defined(FASTCHECK)
529 struct ArrayObject *ao=(struct ArrayObject *) ptr;
530 struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
531 ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
532 ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
535 struct ArrayObject *ao=(struct ArrayObject *) ptr;
536 struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
537 SENQUEUE((void *)ao->___objlocation___, *((void **)&ao_cpy->___objlocation___));
539 } else if (((INTPTR)pointer)==1) {
540 /* Array of pointers */
541 struct ArrayObject *ao=(struct ArrayObject *) ptr;
542 struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
543 #if (defined(DSTM)||defined(FASTCHECK))
544 ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
545 ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
548 SENQUEUE((void *)ao->___objlocation___, *((void **)&ao_cpy->___objlocation___));
550 int length=ao->___length___;
552 for(i=0; i<length; i++) {
553 void *objptr=((void **)(((char *)&ao->___length___)+sizeof(int)))[i];
554 ENQUEUE(objptr, ((void **)(((char *)&ao_cpy->___length___)+sizeof(int)))[i]);
557 INTPTR size=pointer[0];
559 for(i=1; i<=size; i++) {
560 unsigned int offset=pointer[i];
561 void * objptr=*((void **)(((char *)ptr)+offset));
562 ENQUEUE(objptr, *((void **)(((char *)cpy)+offset)));
570 #if defined(THREADS)||defined(DSTM)||defined(STM)
572 pthread_mutex_unlock(&gclistlock);
577 /* Fix up the references from tags. This can't be done earlier,
578 because we don't want tags to keep objects alive */
580 while(taghead!=NULL) {
582 struct pointerblock *tmp=taghead->next;
583 for(i=0; i<tagindex; i++) {
584 struct ___TagDescriptor___ *tagd=taghead->ptrs[i];
585 struct ___Object___ *obj=tagd->flagptr;
586 struct ___TagDescriptor___ *copy=((struct ___TagDescriptor___**)tagd)[1];
588 /* Zero object case */
589 } else if (obj->type==-1) {
590 /* Single object case */
591 copy->flagptr=((struct ___Object___**)obj)[1];
592 } else if (obj->type==OBJECTARRAYTYPE) {
594 struct ArrayObject *ao=(struct ArrayObject *) obj;
598 struct ArrayObject *aonew;
600 /* Count live objects */
601 for(j=0; j<ao->___cachedCode___; j++) {
602 struct ___Object___ * tobj=ARRAYGET(ao, struct ___Object___ *, j);
607 livecount=((livecount-1)/OBJECTARRAYINTERVAL+1)*OBJECTARRAYINTERVAL;
608 aonew=(struct ArrayObject *) tomalloc(sizeof(struct ArrayObject)+sizeof(struct ___Object___*)*livecount);
609 memcpy(aonew, ao, sizeof(struct ArrayObject));
610 aonew->type=OBJECTARRAYTYPE;
611 aonew->___length___=livecount;
613 for(j=0; j<ao->___cachedCode___; j++) {
614 struct ___Object___ * tobj=ARRAYGET(ao, struct ___Object___ *, j);
615 if (tobj->type==-1) {
616 struct ___Object___ * tobjcpy=((struct ___Object___**)tobj)[1];
617 ARRAYSET(aonew, struct ___Object___*, k++,tobjcpy);
620 aonew->___cachedCode___=k;
621 for(; k<livecount; k++) {
622 ARRAYSET(aonew, struct ___Object___*, k, NULL);
625 /* No object live anymore */
636 void * tomalloc(int size) {
637 void * ptr=to_heapptr;
644 #if defined(THREADS)||defined(DSTM)||defined(STM)
645 void checkcollect(void * ptr) {
646 stopforgc((struct garbagelist *)ptr);
651 void checkcollect2(void * ptr) {
652 int ptrarray[]={1, (int)ptr, (int) revertlist};
653 stopforgc((struct garbagelist *)ptrarray);
655 revertlist=(struct ___Object___*)ptrarray[2];
659 void stopforgc(struct garbagelist * ptr) {
661 //just append us to the list
663 ptr=(struct garbagelist *) &ptrstack;
666 ptr=(struct garbagelist *) &arraystack;
672 litem.locklist=pthread_getspecific(threadlocks);
675 litem.tc_size=c_size;
676 litem.tc_table=&c_table;
677 litem.tc_list=&c_list;
678 litem.tc_structs=&c_structs;
679 litem.objlist=newobjs;
681 litem.lockedlist=lockedobjs;
683 litem.base=&memorybase;
687 struct listitem *litem=pthread_getspecific(litemkey);
690 litem->locklist=pthread_getspecific(threadlocks);
693 pthread_mutex_lock(&gclistlock);
695 if ((listcount+1)==threadcount) {
696 //only do wakeup if we are ready to GC
697 pthread_cond_signal(&gccond);
699 pthread_mutex_unlock(&gclistlock);
702 void restartaftergc() {
704 pthread_mutex_lock(&gclock); // Wait for GC
705 pthread_mutex_unlock(&gclock);
707 pthread_mutex_lock(&gclistlock);
709 pthread_mutex_unlock(&gclistlock);
713 #if defined(STM)||defined(THREADS)
714 #define MEMORYBLOCK 65536
715 void * helper(struct garbagelist *, int);
716 void * mygcmalloc(struct garbagelist * stackptr, int size) {
719 if (memorybase==NULL||size>(memorytop-memorybase)) {
720 int toallocate=(size>MEMORYBLOCK)?size:MEMORYBLOCK;
721 memorybase=helper(stackptr, toallocate);
722 memorytop=memorybase+toallocate;
724 char *retvalue=memorybase;
729 void * helper(struct garbagelist * stackptr, int size) {
731 void * mygcmalloc(struct garbagelist * stackptr, int size) {
734 #if defined(THREADS)||defined(DSTM)||defined(STM)
735 while (pthread_mutex_trylock(&gclock)!=0) {
744 if (curr_heapptr>curr_heapgcpoint||curr_heapptr<curr_heapbase) {
745 if (curr_heapbase==0) {
746 /* Need to allocate base heap */
747 curr_heapbase=malloc(INITIALHEAPSIZE);
748 if (curr_heapbase==NULL) {
749 printf("malloc failed. Garbage collector couldn't get enough memory. Try changing heap size.\n");
752 bzero(curr_heapbase, INITIALHEAPSIZE);
753 curr_heaptop=curr_heapbase+INITIALHEAPSIZE;
754 curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(INITIALHEAPSIZE);
755 curr_heapptr=curr_heapbase+size;
757 to_heapbase=malloc(INITIALHEAPSIZE);
758 if (to_heapbase==NULL) {
759 printf("malloc failed. Garbage collector couldn't get enough memory. Try changing heap size.\n");
762 to_heaptop=to_heapbase+INITIALHEAPSIZE;
763 to_heapptr=to_heapbase;
765 #if defined(THREADS)||defined(DSTM)||defined(STM)
766 pthread_mutex_unlock(&gclock);
771 /* Grow the to heap if necessary */
773 INTPTR curr_heapsize=curr_heaptop-curr_heapbase;
774 INTPTR to_heapsize=to_heaptop-to_heapbase;
775 INTPTR last_heapsize=0;
777 last_heapsize=HEAPSIZE(lastgcsize, size);
778 if ((last_heapsize&7)!=0)
779 last_heapsize+=(8-(last_heapsize%8));
781 if (curr_heapsize>last_heapsize)
782 last_heapsize=curr_heapsize;
783 if (last_heapsize>to_heapsize) {
785 to_heapbase=malloc(last_heapsize);
786 if (to_heapbase==NULL) {
787 printf("Error Allocating enough memory\n");
790 to_heaptop=to_heapbase+last_heapsize;
791 to_heapptr=to_heapbase;
795 /* Do our collection */
798 /* Update stat on previous gc size */
799 lastgcsize=(to_heapptr-to_heapbase)+size;
802 printf("Garbage collected: Old bytes: %u\n", curr_heapptr-curr_heapbase);
803 printf("New space: %u\n", to_heapptr-to_heapbase);
804 printf("Total space: %u\n", to_heaptop-to_heapbase);
807 for(i=0;i<MAXSTATS;i++) {
808 if (garbagearray[i]!=0)
809 printf("Type=%d Size=%u\n", i, garbagearray[i]);
813 /* Flip to/curr heaps */
815 void * tmp=to_heapbase;
816 to_heapbase=curr_heapbase;
820 to_heaptop=curr_heaptop;
824 curr_heapptr=to_heapptr+size;
825 curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(curr_heaptop-curr_heapbase);
826 to_heapptr=to_heapbase;
828 /* Not enough room :(, redo gc */
829 if (curr_heapptr>curr_heapgcpoint) {
830 #if defined(THREADS)||defined(DSTM)||defined(STM)
831 pthread_mutex_unlock(&gclock);
833 return mygcmalloc(stackptr, size);
836 bzero(tmp, curr_heaptop-tmp);
837 #if defined(THREADS)||defined(DSTM)||defined(STM)
838 pthread_mutex_unlock(&gclock);
843 #if defined(THREADS)||defined(DSTM)||defined(STM)
844 pthread_mutex_unlock(&gclock);
850 int gc_createcopy(void * orig, void ** copy_ptr) {
855 int type=((int *)orig)[0];
857 *copy_ptr=((void **)orig)[1];
860 if (type<NUMCLASSES) {
861 /* We have a normal object */
863 int size=classsize[type]+sizeof(objheader_t);
864 void *newobj=tomalloc(size);
865 memcpy(newobj,((char *) orig)-sizeof(objheader_t), size);
866 newobj=((char *)newobj)+sizeof(objheader_t);
868 int size=classsize[type];
869 void *newobj=tomalloc(size);
870 memcpy(newobj, orig, size);
873 garbagearray[type]+=size;
876 ((void **)orig)[1]=newobj;
880 /* We have an array */
881 struct ArrayObject *ao=(struct ArrayObject *)orig;
882 int elementsize=classsize[type];
883 int length=ao->___length___;
886 int basesize=length*elementsize;
887 basesize=(basesize+LOWMASK)&HIGHMASK;
888 int versionspace=sizeof(int)*2*(basesize>>INDEXSHIFT);
889 int size=sizeof(struct ArrayObject)+basesize+sizeof(objheader_t)+versionspace;
890 void *newobj=tomalloc(size);
891 memcpy(newobj, ((char*)orig)-sizeof(objheader_t)-versionspace, size);
892 newobj=((char *)newobj)+sizeof(objheader_t)+versionspace;
894 int size=sizeof(struct ArrayObject)+length*elementsize+sizeof(objheader_t);
895 void *newobj=tomalloc(size);
896 memcpy(newobj, ((char*)orig)-sizeof(objheader_t), size);
897 newobj=((char *)newobj)+sizeof(objheader_t);
900 int size=sizeof(struct ArrayObject)+length*elementsize;
901 void *newobj=tomalloc(size);
902 memcpy(newobj, orig, size);
905 garbagearray[type]+=size;
908 ((void **)orig)[1]=newobj;