3 #include "structdefs.h"
5 #include "SimpleHash.h"
7 #include "GenericHashtable.h"
9 #if defined(THREADS) || defined(DSTM) || defined(STM)
13 #include "workschedule.h"
21 #include <DSTM/interface_recovery/dstm.h>
23 #include <DSTM/interface/dstm.h>
30 #include "delaycomp.h"
36 #define INITIALHEAPSIZE 256*1024*1024L
37 #define GCPOINT(x) ((INTPTR)((x)*0.99))
38 /* This define takes in how full the heap is initially and returns a new heap size to use */
39 #define HEAPSIZE(x,y) ((INTPTR)(x+y))*2
42 extern struct genhashtable * activetasks;
44 extern struct parameterwrapper * objectqueues[NUMCLASSES];
46 extern struct genhashtable * failedtasks;
47 extern struct taskparamdescriptor *currtpd;
48 extern struct ctable *forward;
49 extern struct ctable *reverse;
50 extern struct RuntimeHash *fdtoobject;
55 long garbagearray[MAXSTATS];
58 #if defined(THREADS) || defined(DSTM) || defined(STM)||defined(MLP)
60 struct listitem * list=NULL;
63 __thread struct listitem litem;
67 //Need to check if pointers are transaction pointers
68 //this also catches the special flag value of 1 for local copies
70 #define ENQUEUE(orig, dst) \
71 if ((!(((unsigned int)orig)&0x1))) { \
72 if (orig>=curr_heapbase&&orig<curr_heaptop) { \
74 if (gc_createcopy(orig,©)) \
80 #define ENQUEUE(orig, dst) \
81 if (orig>=curr_heapbase&&orig<curr_heaptop) { \
83 if (gc_createcopy(orig,©)) \
87 #define SENQUEUE(orig, dst) \
90 if (gc_createcopy(orig,©)) \
94 #elif defined(FASTCHECK)
95 #define ENQUEUE(orig, dst) \
96 if (((unsigned int)orig)!=1) { \
98 if (gc_createcopy(orig,©)) \
102 #define ENQUEUE(orig, dst) \
104 if (gc_createcopy(orig,©)) \
109 struct pointerblock {
110 void * ptrs[NUMPTRS];
111 struct pointerblock *next;
114 void * curr_heapbase=0;
115 void * curr_heapptr=0;
116 void * curr_heapgcpoint=0;
117 void * curr_heaptop=0;
119 void * to_heapbase=0;
124 struct pointerblock *head=NULL;
126 struct pointerblock *tail=NULL;
128 struct pointerblock *spare=NULL;
130 void enqueue(void *ptr) {
131 if (headindex==NUMPTRS) {
132 struct pointerblock * tmp;
137 tmp=malloc(sizeof(struct pointerblock));
142 head->ptrs[headindex++]=ptr;
146 if (tailindex==NUMPTRS) {
147 struct pointerblock *tmp=tail;
155 return tail->ptrs[tailindex++];
159 void fixobjlist(struct objlist * ptr) {
162 for(i=0;i<ptr->offset;i++) {
163 SENQUEUE(ptr->objs[i], ptr->objs[i]);
169 void fixtable(chashlistnode_t ** tc_table, chashlistnode_t **tc_list, cliststruct_t **cstr, unsigned int tc_size) {
170 unsigned int mask=(tc_size<<4)-1;
171 chashlistnode_t *node=calloc(tc_size, sizeof(chashlistnode_t));
172 chashlistnode_t *ptr=*tc_table;
173 chashlistnode_t *curr;
177 chashlistnode_t *newlist=NULL;
178 for(i=0;i<tc_size;i++) {
181 do { //Inner loop to go through linked lists
183 chashlistnode_t *tmp,*next;
185 if ((key=(void *)curr->key) == 0) { //Exit inner loop if there the first element is 0
186 break; //key = val =0 for element if not present within the hash table
189 if (curr->val>=curr_heapbase&&curr->val<curr_heaptop) {
190 SENQUEUE(curr->val, curr->val);
192 //rewrite transaction cache entry
193 void *vptr=curr->val;
194 int type=((int *)vptr)[0];
195 unsigned INTPTR *pointer=pointerarray[type];
197 //array of primitives - do nothing
198 struct ArrayObject *ao=(struct ArrayObject *) vptr;
199 SENQUEUE((void *)ao->___objlocation___, *((void **)&ao->___objlocation___));
200 } else if (((INTPTR)pointer)==1) {
202 struct ArrayObject *ao=(struct ArrayObject *) vptr;
203 int length=ao->___length___;
205 SENQUEUE((void *)ao->___objlocation___, *((void **)&ao->___objlocation___));
207 int lowindex=ao->lowindex;
208 int highindex=ao->highindex;
210 for(j=lowindex; j<=highindex; j++) {
211 unsigned int lockval;
212 GETLOCKVAL(lockval, ao, j);
213 if (lockval!=STMNONE) {
214 int lowi=(j<<INDEXSHIFT)/sizeof(void *);
215 int highi=lowi+(INDEXLENGTH/sizeof(void *));
216 for(i=lowi; i<highi;i++) {
218 for(i=0; i<length; i++) {
220 void *objptr=((void **)(((char *)&ao->___length___)+sizeof(int)))[i];
221 SENQUEUE(objptr, ((void **)(((char *)&ao->___length___)+sizeof(int)))[i]);
228 INTPTR size=pointer[0];
230 for(i=1; i<=size; i++) {
231 unsigned int offset=pointer[i];
232 void * objptr=*((void **)(((char *)vptr)+offset));
233 SENQUEUE(objptr, *((void **)(((char *)vptr)+offset)));
239 index = (((unsigned INTPTR)key) & mask) >>4;
243 // Insert into the new table
245 tmp->key = curr->key;
246 tmp->val = curr->val;
249 } else if (isfirst) {
250 chashlistnode_t *newnode;
251 if ((*cstr)->num<NUMCLIST) {
252 newnode=&(*cstr)->array[(*cstr)->num];
256 cliststruct_t *tcl=calloc(1,sizeof(cliststruct_t));
259 newnode=&tcl->array[0];
262 newnode->key = curr->key;
263 newnode->val = curr->val;
264 newnode->next = tmp->next;
265 newnode->lnext=newlist;
271 curr->next=tmp->next;
285 if ((head==tail)&&(tailindex==headindex))
291 struct pointerblock *taghead=NULL;
294 void enqueuetag(struct ___TagDescriptor___ *ptr) {
295 if (tagindex==NUMPTRS) {
296 struct pointerblock * tmp=malloc(sizeof(struct pointerblock));
301 taghead->ptrs[tagindex++]=ptr;
305 #if defined(STM)||defined(THREADS)||defined(MLP)
306 __thread char * memorybase=NULL;
307 __thread char * memorytop=NULL;
311 void collect(struct garbagelist * stackptr) {
312 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
314 pthread_mutex_lock(&gclistlock);
316 if ((listcount+1)==threadcount) {
317 break; /* Have all other threads stopped */
319 pthread_cond_wait(&gccond, &gclistlock);
323 ptrstack.prev=stackptr;
324 stackptr=(struct garbagelist *) &ptrstack;
325 #if defined(STMARRAY)&&!defined(DUALVIEW)
326 arraystack.prev=stackptr;
327 stackptr=(struct garbagelist *) &arraystack;
334 for(i=0;i<MAXSTATS;i++)
342 head=tail=malloc(sizeof(struct pointerblock));
348 taghead=malloc(sizeof(struct pointerblock));
355 fixtable(&c_table, &c_list, &c_structs, c_size);
358 fixobjlist(lockedobjs);
362 #if defined(STM)||defined(THREADS)||defined(MLP)
366 /* Check current stack */
367 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
369 struct listitem *listptr=list;
373 while(stackptr!=NULL) {
375 for(i=0; i<stackptr->size; i++) {
376 void * orig=stackptr->array[i];
377 ENQUEUE(orig, stackptr->array[i]);
379 stackptr=stackptr->next;
381 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
382 /* Go to next thread */
385 if (listptr==&litem) {
386 listptr=listptr->next;
390 struct listitem *litem=pthread_getspecific(litemkey);
391 if (listptr==litem) {
392 listptr=listptr->next;
399 void * orig=listptr->locklist;
400 ENQUEUE(orig, listptr->locklist);
403 if ((*listptr->tc_table)!=NULL) {
404 fixtable(listptr->tc_table, listptr->tc_list, listptr->tc_structs, listptr->tc_size);
405 fixobjlist(listptr->objlist);
407 fixobjlist(listptr->lockedlist);
411 #if defined(STM)||defined(THREADS)||defined(MLP)
412 *(listptr->base)=NULL;
414 stackptr=listptr->stackptr;
415 listptr=listptr->next;
423 ENQUEUE(___fcrevert___, ___fcrevert___);
428 /* Update objectsets */
430 for(i=0; i<NUMCLASSES; i++) {
431 #if !defined(MULTICORE)
432 struct parameterwrapper * p=objectqueues[i];
434 struct ObjectHash * set=p->objectset;
435 struct ObjectNode * ptr=set->listhead;
437 void *orig=(void *)ptr->key;
438 ENQUEUE(orig, *((void **)(&ptr->key)));
441 ObjectHashrehash(set); /* Rehash the table */
450 struct cnode * ptr=forward->listhead;
452 void * orig=(void *)ptr->key;
453 ENQUEUE(orig, *((void **)(&ptr->key)));
456 crehash(forward); /* Rehash the table */
460 struct cnode * ptr=reverse->listhead;
462 void *orig=(void *)ptr->val;
463 ENQUEUE(orig, *((void**)(&ptr->val)));
470 struct RuntimeNode * ptr=fdtoobject->listhead;
472 void *orig=(void *)ptr->data;
473 ENQUEUE(orig, *((void**)(&ptr->data)));
479 /* Update current task descriptor */
481 for(i=0; i<currtpd->numParameters; i++) {
482 void *orig=currtpd->parameterArray[i];
483 ENQUEUE(orig, currtpd->parameterArray[i]);
488 /* Update active tasks */
490 struct genpointerlist * ptr=activetasks->list;
492 struct taskparamdescriptor *tpd=ptr->src;
494 for(i=0; i<tpd->numParameters; i++) {
495 void * orig=tpd->parameterArray[i];
496 ENQUEUE(orig, tpd->parameterArray[i]);
500 genrehash(activetasks);
503 /* Update failed tasks */
505 struct genpointerlist * ptr=failedtasks->list;
507 struct taskparamdescriptor *tpd=ptr->src;
509 for(i=0; i<tpd->numParameters; i++) {
510 void * orig=tpd->parameterArray[i];
511 ENQUEUE(orig, tpd->parameterArray[i]);
515 genrehash(failedtasks);
520 void * ptr=dequeue();
522 int type=((int *)cpy)[0];
523 unsigned INTPTR * pointer;
527 /* Nothing is inside */
532 pointer=pointerarray[type];
534 /* Array of primitives */
536 #if defined(DSTM)||defined(FASTCHECK)
537 struct ArrayObject *ao=(struct ArrayObject *) ptr;
538 struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
539 ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
540 ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
543 struct ArrayObject *ao=(struct ArrayObject *) ptr;
544 struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
545 SENQUEUE((void *)ao->___objlocation___, *((void **)&ao_cpy->___objlocation___));
547 } else if (((INTPTR)pointer)==1) {
548 /* Array of pointers */
549 struct ArrayObject *ao=(struct ArrayObject *) ptr;
550 struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
551 #if (defined(DSTM)||defined(FASTCHECK))
552 ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
553 ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
556 SENQUEUE((void *)ao->___objlocation___, *((void **)&ao_cpy->___objlocation___));
558 int length=ao->___length___;
560 for(i=0; i<length; i++) {
561 void *objptr=((void **)(((char *)&ao->___length___)+sizeof(int)))[i];
562 ENQUEUE(objptr, ((void **)(((char *)&ao_cpy->___length___)+sizeof(int)))[i]);
565 INTPTR size=pointer[0];
567 for(i=1; i<=size; i++) {
568 unsigned int offset=pointer[i];
569 void * objptr=*((void **)(((char *)ptr)+offset));
570 ENQUEUE(objptr, *((void **)(((char *)cpy)+offset)));
578 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
580 pthread_mutex_unlock(&gclistlock);
585 /* Fix up the references from tags. This can't be done earlier,
586 because we don't want tags to keep objects alive */
588 while(taghead!=NULL) {
590 struct pointerblock *tmp=taghead->next;
591 for(i=0; i<tagindex; i++) {
592 struct ___TagDescriptor___ *tagd=taghead->ptrs[i];
593 struct ___Object___ *obj=tagd->flagptr;
594 struct ___TagDescriptor___ *copy=((struct ___TagDescriptor___**)tagd)[1];
596 /* Zero object case */
597 } else if (obj->type==-1) {
598 /* Single object case */
599 copy->flagptr=((struct ___Object___**)obj)[1];
600 } else if (obj->type==OBJECTARRAYTYPE) {
602 struct ArrayObject *ao=(struct ArrayObject *) obj;
606 struct ArrayObject *aonew;
608 /* Count live objects */
609 for(j=0; j<ao->___cachedCode___; j++) {
610 struct ___Object___ * tobj=ARRAYGET(ao, struct ___Object___ *, j);
615 livecount=((livecount-1)/OBJECTARRAYINTERVAL+1)*OBJECTARRAYINTERVAL;
616 aonew=(struct ArrayObject *) tomalloc(sizeof(struct ArrayObject)+sizeof(struct ___Object___*)*livecount);
617 memcpy(aonew, ao, sizeof(struct ArrayObject));
618 aonew->type=OBJECTARRAYTYPE;
619 aonew->___length___=livecount;
621 for(j=0; j<ao->___cachedCode___; j++) {
622 struct ___Object___ * tobj=ARRAYGET(ao, struct ___Object___ *, j);
623 if (tobj->type==-1) {
624 struct ___Object___ * tobjcpy=((struct ___Object___**)tobj)[1];
625 ARRAYSET(aonew, struct ___Object___*, k++,tobjcpy);
628 aonew->___cachedCode___=k;
629 for(; k<livecount; k++) {
630 ARRAYSET(aonew, struct ___Object___*, k, NULL);
633 /* No object live anymore */
644 void * tomalloc(int size) {
645 void * ptr=to_heapptr;
652 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
653 void checkcollect(void * ptr) {
654 stopforgc((struct garbagelist *)ptr);
659 void checkcollect2(void * ptr) {
660 int ptrarray[]={1, (int)ptr, (int) revertlist};
661 stopforgc((struct garbagelist *)ptrarray);
663 revertlist=(struct ___Object___*)ptrarray[2];
667 void stopforgc(struct garbagelist * ptr) {
669 //just append us to the list
671 ptr=(struct garbagelist *) &ptrstack;
672 #if defined(STMARRAY)&&!defined(DUALVIEW)
674 ptr=(struct garbagelist *) &arraystack;
680 litem.locklist=pthread_getspecific(threadlocks);
682 #if defined(STM)||defined(THREADS)||defined(MLP)
683 litem.base=&memorybase;
686 litem.tc_size=c_size;
687 litem.tc_table=&c_table;
688 litem.tc_list=&c_list;
689 litem.tc_structs=&c_structs;
690 litem.objlist=newobjs;
692 litem.lockedlist=lockedobjs;
697 struct listitem *litem=pthread_getspecific(litemkey);
700 litem->locklist=pthread_getspecific(threadlocks);
703 pthread_mutex_lock(&gclistlock);
705 if ((listcount+1)==threadcount) {
706 //only do wakeup if we are ready to GC
707 pthread_cond_signal(&gccond);
709 pthread_mutex_unlock(&gclistlock);
712 void restartaftergc() {
714 pthread_mutex_lock(&gclock); // Wait for GC
715 pthread_mutex_unlock(&gclock);
717 pthread_mutex_lock(&gclistlock);
719 pthread_mutex_unlock(&gclistlock);
723 #if defined(STM)||defined(THREADS)||defined(MLP)
724 #define MEMORYBLOCK 65536
725 void * helper(struct garbagelist *, int);
726 void * mygcmalloc(struct garbagelist * stackptr, int size) {
729 if (memorybase==NULL||size>(memorytop-memorybase)) {
730 int toallocate=(size>MEMORYBLOCK)?size:MEMORYBLOCK;
731 memorybase=helper(stackptr, toallocate);
732 memorytop=memorybase+toallocate;
734 char *retvalue=memorybase;
739 void * helper(struct garbagelist * stackptr, int size) {
741 void * mygcmalloc(struct garbagelist * stackptr, int size) {
744 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
745 while (pthread_mutex_trylock(&gclock)!=0) {
754 if (curr_heapptr>curr_heapgcpoint||curr_heapptr<curr_heapbase) {
755 if (curr_heapbase==0) {
756 /* Need to allocate base heap */
757 curr_heapbase=malloc(INITIALHEAPSIZE);
758 if (curr_heapbase==NULL) {
759 printf("malloc failed. Garbage collector couldn't get enough memory. Try changing heap size.\n");
762 bzero(curr_heapbase, INITIALHEAPSIZE);
763 curr_heaptop=curr_heapbase+INITIALHEAPSIZE;
764 curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(INITIALHEAPSIZE);
765 curr_heapptr=curr_heapbase+size;
767 to_heapbase=malloc(INITIALHEAPSIZE);
768 if (to_heapbase==NULL) {
769 printf("malloc failed. Garbage collector couldn't get enough memory. Try changing heap size.\n");
772 to_heaptop=to_heapbase+INITIALHEAPSIZE;
773 to_heapptr=to_heapbase;
775 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
776 pthread_mutex_unlock(&gclock);
781 /* Grow the to heap if necessary */
783 INTPTR curr_heapsize=curr_heaptop-curr_heapbase;
784 INTPTR to_heapsize=to_heaptop-to_heapbase;
785 INTPTR last_heapsize=0;
787 last_heapsize=HEAPSIZE(lastgcsize, size);
788 if ((last_heapsize&7)!=0)
789 last_heapsize+=(8-(last_heapsize%8));
791 if (curr_heapsize>last_heapsize)
792 last_heapsize=curr_heapsize;
793 if (last_heapsize>to_heapsize) {
795 to_heapbase=malloc(last_heapsize);
796 if (to_heapbase==NULL) {
797 printf("Error Allocating enough memory\n");
800 to_heaptop=to_heapbase+last_heapsize;
801 to_heapptr=to_heapbase;
805 /* Do our collection */
808 /* Update stat on previous gc size */
809 lastgcsize=(to_heapptr-to_heapbase)+size;
812 printf("Garbage collected: Old bytes: %u\n", curr_heapptr-curr_heapbase);
813 printf("New space: %u\n", to_heapptr-to_heapbase);
814 printf("Total space: %u\n", to_heaptop-to_heapbase);
817 for(i=0;i<MAXSTATS;i++) {
818 if (garbagearray[i]!=0)
819 printf("Type=%d Size=%u\n", i, garbagearray[i]);
823 /* Flip to/curr heaps */
825 void * tmp=to_heapbase;
826 to_heapbase=curr_heapbase;
830 to_heaptop=curr_heaptop;
834 curr_heapptr=to_heapptr+size;
835 curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(curr_heaptop-curr_heapbase);
836 to_heapptr=to_heapbase;
838 /* Not enough room :(, redo gc */
839 if (curr_heapptr>curr_heapgcpoint) {
840 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
841 pthread_mutex_unlock(&gclock);
843 return mygcmalloc(stackptr, size);
846 bzero(tmp, curr_heaptop-tmp);
847 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
848 pthread_mutex_unlock(&gclock);
853 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
854 pthread_mutex_unlock(&gclock);
860 int gc_createcopy(void * orig, void ** copy_ptr) {
865 int type=((int *)orig)[0];
867 *copy_ptr=((void **)orig)[1];
870 if (type<NUMCLASSES) {
871 /* We have a normal object */
873 int size=classsize[type]+sizeof(objheader_t);
874 void *newobj=tomalloc(size);
875 memcpy(newobj,((char *) orig)-sizeof(objheader_t), size);
876 newobj=((char *)newobj)+sizeof(objheader_t);
878 int size=classsize[type];
879 void *newobj=tomalloc(size);
880 memcpy(newobj, orig, size);
883 garbagearray[type]+=size;
886 ((void **)orig)[1]=newobj;
890 /* We have an array */
891 struct ArrayObject *ao=(struct ArrayObject *)orig;
892 int elementsize=classsize[type];
893 int length=ao->___length___;
896 int basesize=length*elementsize;
897 basesize=(basesize+LOWMASK)&HIGHMASK;
898 int versionspace=sizeof(int)*2*(basesize>>INDEXSHIFT);
899 int size=sizeof(struct ArrayObject)+basesize+sizeof(objheader_t)+versionspace;
900 void *newobj=tomalloc(size);
901 memcpy(newobj, ((char*)orig)-sizeof(objheader_t)-versionspace, size);
902 newobj=((char *)newobj)+sizeof(objheader_t)+versionspace;
904 int size=sizeof(struct ArrayObject)+length*elementsize+sizeof(objheader_t);
905 void *newobj=tomalloc(size);
906 memcpy(newobj, ((char*)orig)-sizeof(objheader_t), size);
907 newobj=((char *)newobj)+sizeof(objheader_t);
910 int size=sizeof(struct ArrayObject)+length*elementsize;
911 void *newobj=tomalloc(size);
912 memcpy(newobj, orig, size);
915 garbagearray[type]+=size;
918 ((void **)orig)[1]=newobj;