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"
34 #ifndef INITIALHEAPSIZE_MB
35 #define INITIALHEAPSIZE_MB (256)
38 #define INITIALHEAPSIZE INITIALHEAPSIZE_MB*1024*1024L
39 #define GCPOINT(x) ((INTPTR)((x)*0.99))
40 /* This define takes in how full the heap is initially and returns a new heap size to use */
41 #define HEAPSIZE(x,y) ((INTPTR)(x+y))*2
45 long garbagearray[MAXSTATS];
48 #if defined(THREADS) || defined(DSTM) || defined(STM)||defined(MLP)
50 struct listitem * list=NULL;
53 __thread struct listitem litem;
57 //Need to check if pointers are transaction pointers
58 //this also catches the special flag value of 1 for local copies
60 void * curr_heapbase=0;
61 void * curr_heapptr=0;
62 void * curr_heapgcpoint=0;
63 void * curr_heaptop=0;
71 struct pointerblock *head=NULL;
73 struct pointerblock *tail=NULL;
75 struct pointerblock *spare=NULL;
77 void enqueue(void *ptr) {
78 if (headindex==NUMPTRS) {
79 struct pointerblock * tmp;
83 } else tmp=malloc(sizeof(struct pointerblock));
88 head->ptrs[headindex++]=ptr;
92 if (tailindex==NUMPTRS) {
93 struct pointerblock *tmp=tail;
101 return tail->ptrs[tailindex++];
105 void fixobjlist(struct objlist * ptr) {
108 for(i=0; i<ptr->offset; i++) {
109 SENQUEUE(ptr->objs[i], ptr->objs[i]);
115 void fixtable(chashlistnode_t ** tc_table, chashlistnode_t **tc_list, cliststruct_t **cstr, unsigned int tc_size) {
116 unsigned int mask=(tc_size<<4)-1;
117 chashlistnode_t *node=calloc(tc_size, sizeof(chashlistnode_t));
118 chashlistnode_t *ptr=*tc_table;
119 chashlistnode_t *curr;
123 chashlistnode_t *newlist=NULL;
124 for(i=0; i<tc_size; i++) {
127 do { //Inner loop to go through linked lists
129 chashlistnode_t *tmp,*next;
131 if ((key=(void *)curr->key) == 0) { //Exit inner loop if there the first element is 0
132 break; //key = val =0 for element if not present within the hash table
135 if (curr->val>=curr_heapbase&&curr->val<curr_heaptop) {
136 SENQUEUE(curr->val, curr->val);
138 //rewrite transaction cache entry
139 void *vptr=curr->val;
140 int type=((int *)vptr)[0];
141 unsigned INTPTR *pointer=pointerarray[type];
143 //array of primitives - do nothing
144 struct ArrayObject *ao=(struct ArrayObject *) vptr;
145 SENQUEUE((void *)ao->___objlocation___, *((void **)&ao->___objlocation___));
146 } else if (((INTPTR)pointer)==1) {
148 struct ArrayObject *ao=(struct ArrayObject *) vptr;
149 int length=ao->___length___;
151 SENQUEUE((void *)ao->___objlocation___, *((void **)&ao->___objlocation___));
153 int lowindex=ao->lowindex;
154 int highindex=ao->highindex;
156 for(j=lowindex; j<=highindex; j++) {
157 unsigned int lockval;
158 GETLOCKVAL(lockval, ao, j);
159 if (lockval!=STMNONE) {
160 int lowi=(j<<INDEXSHIFT)/sizeof(void *);
161 int highi=lowi+(INDEXLENGTH/sizeof(void *));
162 for(i=lowi; i<highi; i++) {
164 for(i=0; i<length; i++) {
166 void *objptr=((void **)(((char *)&ao->___length___)+sizeof(int)))[i];
167 SENQUEUE(objptr, ((void **)(((char *)&ao->___length___)+sizeof(int)))[i]);
174 INTPTR size=pointer[0];
176 for(i=1; i<=size; i++) {
177 unsigned int offset=pointer[i];
178 void * objptr=*((void **)(((char *)vptr)+offset));
179 SENQUEUE(objptr, *((void **)(((char *)vptr)+offset)));
185 index = (((unsigned INTPTR)key) & mask) >>4;
189 // Insert into the new table
191 tmp->key = curr->key;
192 tmp->val = curr->val;
195 } else if (isfirst) {
196 chashlistnode_t *newnode;
197 if ((*cstr)->num<NUMCLIST) {
198 newnode=&(*cstr)->array[(*cstr)->num];
202 cliststruct_t *tcl=calloc(1,sizeof(cliststruct_t));
205 newnode=&tcl->array[0];
208 newnode->key = curr->key;
209 newnode->val = curr->val;
210 newnode->next = tmp->next;
211 newnode->lnext=newlist;
217 curr->next=tmp->next;
232 if ((head==tail)&&(tailindex==headindex))
238 #if defined(STM)||defined(THREADS)||defined(MLP)
240 __thread char * memorybase=NULL;
241 __thread char * memorytop=NULL;
249 head=tail=malloc(sizeof(struct pointerblock));
255 taghead=malloc(sizeof(struct pointerblock));
262 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
264 pthread_mutex_lock(&gclistlock);
266 if ((listcount+1)==threadcount) {
267 break; /* Have all other threads stopped */
269 pthread_cond_wait(&gccond, &gclistlock);
276 for(i=0; i<MAXSTATS; i++)
283 litem.tc_size=c_size;
284 litem.tc_table=&c_table;
285 litem.tc_list=&c_list;
286 litem.tc_structs=&c_structs;
287 litem.objlist=newobjs;
289 litem.lockedlist=lockedobjs;
292 #if defined(STM)||defined(THREADS)||defined(MLP)
294 struct listitem *litem=pthread_getspecific(litemkey);
295 litem->base=((char **)pthread_getspecific(memorybasekey));
297 litem.base=&memorybase;
302 void searchglobalroots() {
303 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
306 struct garbagelist * stackptr=(struct garbagelist *)global_defs_p;
307 for(i=0; i<stackptr->size; i++) {
308 void * orig=stackptr->array[i];
309 ENQUEUE(orig, stackptr->array[i]);
315 void searchstack(struct garbagelist *stackptr) {
316 while(stackptr!=NULL) {
318 for(i=0; i<stackptr->size; i++) {
319 void * orig=stackptr->array[i];
320 ENQUEUE(orig, stackptr->array[i]);
322 stackptr=stackptr->next;
327 void searchjnitable(struct jnireferences *jniptr) {
328 while(jniptr!=NULL) {
331 for(i=0; i<jniptr->index; i++) {
332 ENQUEUE((struct ___Object___ *)jniptr->array[i].ref, *((struct ___Object___**)&jniptr->array[i].ref));
340 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
341 void searchthreadroots(struct garbagelist * stackptr) {
342 /* Check current stack */
343 struct listitem *listptr=list;
345 struct listitem *litem=pthread_getspecific(litemkey);
346 litem->stackptr=stackptr;
348 litem.stackptr=stackptr;
351 while(listptr!=NULL) {
352 searchstack(listptr->stackptr);
354 struct lockvector * lvector=listptr->lvector;
356 for(i=0; i<lvector->index; i++) {
357 struct ___Object___ *orig=lvector->locks[i].object;
358 ENQUEUE(orig, lvector->locks[i].object);
362 searchjnitable(*listptr->jnirefs);
365 if ((*listptr->tc_table)!=NULL) {
366 fixtable(listptr->tc_table, listptr->tc_list, listptr->tc_structs, listptr->tc_size);
367 fixobjlist(listptr->objlist);
369 fixobjlist(listptr->lockedlist);
373 #if defined(STM)||defined(THREADS)||defined(MLP)
374 *(listptr->base)=NULL;
377 // update forward list & memory queue for all running SESEs.
378 if (listptr->seseCommon!=NULL) {
379 updateForwardList(&((SESEcommon*)listptr->seseCommon)->forwardList,FALSE);
380 updateMemoryQueue((SESEcommon*)(listptr->seseCommon));
383 listptr=listptr->next;
388 void searchroots(struct garbagelist * stackptr) {
389 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
390 searchthreadroots(stackptr);
392 searchstack(stackptr);
395 ENQUEUE(___fcrevert___, ___fcrevert___);
406 void collect(struct garbagelist * stackptr) {
410 ptrstack.prev=stackptr;
411 stackptr=(struct garbagelist *) &ptrstack;
412 #if defined(STMARRAY)&&!defined(DUALVIEW)
413 arraystack.prev=stackptr;
414 stackptr=(struct garbagelist *) &arraystack;
418 searchroots(stackptr);
421 void * ptr=dequeue();
423 int type=((int *)cpy)[0];
424 unsigned INTPTR * pointer;
428 /* Nothing is inside */
433 pointer=pointerarray[type];
435 /* Array of primitives */
437 #if defined(DSTM)||defined(FASTCHECK)
438 struct ArrayObject *ao=(struct ArrayObject *) ptr;
439 struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
440 ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
441 ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
444 struct ArrayObject *ao=(struct ArrayObject *) ptr;
445 struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
446 SENQUEUE((void *)ao->___objlocation___, *((void **)&ao_cpy->___objlocation___));
448 } else if (((INTPTR)pointer)==1) {
449 /* Array of pointers */
450 struct ArrayObject *ao=(struct ArrayObject *) ptr;
451 struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
452 #if (defined(DSTM)||defined(FASTCHECK))
453 ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
454 ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
457 SENQUEUE((void *)ao->___objlocation___, *((void **)&ao_cpy->___objlocation___));
459 int length=ao->___length___;
461 for(i=0; i<length; i++) {
462 void *objptr=((void **)(((char *)&ao->___length___)+sizeof(int)))[i];
463 ENQUEUE(objptr, ((void **)(((char *)&ao_cpy->___length___)+sizeof(int)))[i]);
466 INTPTR size=pointer[0];
468 for(i=1; i<=size; i++) {
469 unsigned int offset=pointer[i];
470 void * objptr=*((void **)(((char *)ptr)+offset));
471 ENQUEUE(objptr, *((void **)(((char *)cpy)+offset)));
479 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
481 pthread_mutex_unlock(&gclistlock);
485 void * tomalloc(int size) {
486 void * ptr=to_heapptr;
493 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
494 void checkcollect(void * ptr) {
495 stopforgc((struct garbagelist *)ptr);
500 void checkcollect2(void * ptr) {
501 int ptrarray[]={1, (int)ptr, (int) revertlist};
502 stopforgc((struct garbagelist *)ptrarray);
504 revertlist=(struct ___Object___*)ptrarray[2];
508 void stopforgc(struct garbagelist * ptr) {
510 //just append us to the list
512 ptr=(struct garbagelist *) &ptrstack;
513 #if defined(STMARRAY)&&!defined(DUALVIEW)
515 ptr=(struct garbagelist *) &arraystack;
520 #if defined(STM)||defined(THREADS)||defined(MLP)
521 litem.base=&memorybase;
524 litem.tc_size=c_size;
525 litem.tc_table=&c_table;
526 litem.tc_list=&c_list;
527 litem.tc_structs=&c_structs;
528 litem.objlist=newobjs;
530 litem.lockedlist=lockedobjs;
535 struct listitem *litem=pthread_getspecific(litemkey);
537 #if defined(STM)||defined(THREADS)||defined(MLP)
538 litem->base=pthread_getspecific(memorybasekey);
541 pthread_mutex_lock(&gclistlock);
543 if ((listcount+1)==threadcount) {
544 //only do wakeup if we are ready to GC
545 pthread_cond_signal(&gccond);
547 pthread_mutex_unlock(&gclistlock);
550 void restartaftergc() {
552 pthread_mutex_lock(&gclock); // Wait for GC
553 pthread_mutex_unlock(&gclock);
555 pthread_mutex_lock(&gclistlock);
557 pthread_mutex_unlock(&gclistlock);
560 struct listitem *litem=pthread_getspecific(litemkey);
566 #if defined(STM)||defined(THREADS)||defined(MLP)
567 #define MEMORYBLOCK 65536
568 void * helper(struct garbagelist *, int);
569 void * mygcmalloc(struct garbagelist * stackptr, int size) {
573 char * memorybase=*(char **)pthread_getspecific(memorybasekey);
574 char * memorytop=*(char **)pthread_getspecific(memorytopkey);
576 if (memorybase==NULL||size>(memorytop-memorybase)) {
577 int toallocate=(size>MEMORYBLOCK) ? size : MEMORYBLOCK;
578 memorybase=helper(stackptr, toallocate);
579 bzero(memorybase, toallocate);
580 memorytop=memorybase+toallocate;
582 char *retvalue=memorybase;
585 *(char **)pthread_getspecific(memorybasekey)=memorybase;
586 *(char **)pthread_getspecific(memorytopkey)=memorytop;
591 void * helper(struct garbagelist * stackptr, int size) {
593 void * mygcmalloc(struct garbagelist * stackptr, int size) {
596 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
597 while (pthread_mutex_trylock(&gclock)!=0) {
606 if (curr_heapptr>curr_heapgcpoint||curr_heapptr<curr_heapbase) {
607 if (curr_heapbase==0) {
608 /* Need to allocate base heap */
609 curr_heapbase=malloc(INITIALHEAPSIZE);
610 if (curr_heapbase==NULL) {
611 printf("malloc failed. Garbage colletcor couldn't get enough memory. Try changing heap size.\n");
614 #if defined(STM)||defined(THREADS)||defined(MLP)
616 bzero(curr_heapbase, INITIALHEAPSIZE);
618 curr_heaptop=curr_heapbase+INITIALHEAPSIZE;
619 curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(INITIALHEAPSIZE);
620 curr_heapptr=curr_heapbase+size;
622 to_heapbase=malloc(INITIALHEAPSIZE);
623 if (to_heapbase==NULL) {
624 printf("malloc failed. Garbage collector couldn't get enough memory. Try changing heap size.\n");
628 to_heaptop=to_heapbase+INITIALHEAPSIZE;
629 to_heapptr=to_heapbase;
631 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
632 pthread_mutex_unlock(&gclock);
637 /* Grow the to heap if necessary */
639 INTPTR curr_heapsize=curr_heaptop-curr_heapbase;
640 INTPTR to_heapsize=to_heaptop-to_heapbase;
641 INTPTR last_heapsize=0;
643 last_heapsize=HEAPSIZE(lastgcsize, size);
644 if ((last_heapsize&7)!=0)
645 last_heapsize+=(8-(last_heapsize%8));
647 if (curr_heapsize>last_heapsize)
648 last_heapsize=curr_heapsize;
649 if (last_heapsize>to_heapsize) {
651 to_heapbase=malloc(last_heapsize);
652 if (to_heapbase==NULL) {
653 printf("Error Allocating enough memory\n");
656 to_heaptop=to_heapbase+last_heapsize;
657 to_heapptr=to_heapbase;
661 /* Do our collection */
664 /* Update stat on previous gc size */
665 lastgcsize=(to_heapptr-to_heapbase)+size;
668 printf("Garbage collected: Old bytes: %u\n", curr_heapptr-curr_heapbase);
669 printf("New space: %u\n", to_heapptr-to_heapbase);
670 printf("Total space: %u\n", to_heaptop-to_heapbase);
673 for(i=0; i<MAXSTATS; i++) {
674 if (garbagearray[i]!=0)
675 printf("Type=%d Size=%u\n", i, garbagearray[i]);
679 /* Flip to/curr heaps */
681 void * tmp=to_heapbase;
682 to_heapbase=curr_heapbase;
686 to_heaptop=curr_heaptop;
690 curr_heapptr=to_heapptr+size;
691 curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(curr_heaptop-curr_heapbase);
692 to_heapptr=to_heapbase;
694 /* Not enough room :(, redo gc */
695 if (curr_heapptr>curr_heapgcpoint) {
696 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
697 pthread_mutex_unlock(&gclock);
699 return mygcmalloc(stackptr, size);
702 bzero(tmp, curr_heaptop-tmp);
703 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
704 pthread_mutex_unlock(&gclock);
709 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
710 pthread_mutex_unlock(&gclock);
716 int gc_createcopy(void * orig, void ** copy_ptr) {
721 int type=((int *)orig)[0];
723 *copy_ptr=((void **)orig)[1];
726 if (type<NUMCLASSES) {
727 /* We have a normal object */
729 int size=classsize[type]+sizeof(objheader_t);
730 void *newobj=tomalloc(size);
731 memcpy(newobj,((char *) orig)-sizeof(objheader_t), size);
732 newobj=((char *)newobj)+sizeof(objheader_t);
734 int size=classsize[type];
735 void *newobj=tomalloc(size);
736 memcpy(newobj, orig, size);
739 garbagearray[type]+=size;
742 ((void **)orig)[1]=newobj;
746 /* We have an array */
747 struct ArrayObject *ao=(struct ArrayObject *)orig;
748 int elementsize=classsize[type];
749 int length=ao->___length___;
752 int basesize=length*elementsize;
753 basesize=(basesize+LOWMASK)&HIGHMASK;
754 int versionspace=sizeof(int)*2*(basesize>>INDEXSHIFT);
755 int size=sizeof(struct ArrayObject)+basesize+sizeof(objheader_t)+versionspace;
756 void *newobj=tomalloc(size);
757 memcpy(newobj, ((char*)orig)-sizeof(objheader_t)-versionspace, size);
758 newobj=((char *)newobj)+sizeof(objheader_t)+versionspace;
760 int size=sizeof(struct ArrayObject)+length*elementsize+sizeof(objheader_t);
761 void *newobj=tomalloc(size);
762 memcpy(newobj, ((char*)orig)-sizeof(objheader_t), size);
763 newobj=((char *)newobj)+sizeof(objheader_t);
766 int size=sizeof(struct ArrayObject)+length*elementsize;
767 void *newobj=tomalloc(size);
768 memcpy(newobj, orig, size);
771 garbagearray[type]+=size;
774 ((void **)orig)[1]=newobj;
781 int within(void *ptr) { //debug function
782 if(ptr>curr_heapptr || ptr<curr_heapbase) {
783 __asm__ __volatile__ ("int $3"); // breakpoint