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"
35 #ifndef INITIALHEAPSIZE_MB
36 #define INITIALHEAPSIZE_MB (256)
39 #define INITIALHEAPSIZE INITIALHEAPSIZE_MB*1024*1024L
40 #define GCPOINT(x) ((INTPTR)((x)*0.99))
41 /* This define takes in how full the heap is initially and returns a new heap size to use */
42 #define HEAPSIZE(x,y) ((INTPTR)(x+y))*2
46 long garbagearray[MAXSTATS];
49 #if defined(THREADS) || defined(DSTM) || defined(STM)||defined(MLP)
51 struct listitem * list=NULL;
54 __thread struct listitem litem;
58 //Need to check if pointers are transaction pointers
59 //this also catches the special flag value of 1 for local copies
61 void * curr_heapbase=0;
62 void * curr_heapptr=0;
63 void * curr_heapgcpoint=0;
64 void * curr_heaptop=0;
72 struct pointerblock *head=NULL;
74 struct pointerblock *tail=NULL;
76 struct pointerblock *spare=NULL;
78 void enqueue(void *ptr) {
79 if (headindex==NUMPTRS) {
80 struct pointerblock * tmp;
84 } else tmp=malloc(sizeof(struct pointerblock));
89 head->ptrs[headindex++]=ptr;
93 if (tailindex==NUMPTRS) {
94 struct pointerblock *tmp=tail;
102 return tail->ptrs[tailindex++];
106 void fixobjlist(struct objlist * ptr) {
109 for(i=0; i<ptr->offset; i++) {
110 SENQUEUE(ptr->objs[i], ptr->objs[i]);
116 void fixtable(chashlistnode_t ** tc_table, chashlistnode_t **tc_list, cliststruct_t **cstr, unsigned int tc_size) {
117 unsigned int mask=(tc_size<<4)-1;
118 chashlistnode_t *node=calloc(tc_size, sizeof(chashlistnode_t));
119 chashlistnode_t *ptr=*tc_table;
120 chashlistnode_t *curr;
124 chashlistnode_t *newlist=NULL;
125 for(i=0; i<tc_size; i++) {
128 do { //Inner loop to go through linked lists
130 chashlistnode_t *tmp,*next;
132 if ((key=(void *)curr->key) == 0) { //Exit inner loop if there the first element is 0
133 break; //key = val =0 for element if not present within the hash table
136 if (curr->val>=curr_heapbase&&curr->val<curr_heaptop) {
137 SENQUEUE(curr->val, curr->val);
139 //rewrite transaction cache entry
140 void *vptr=curr->val;
141 int type=((int *)vptr)[0];
142 unsigned INTPTR *pointer=pointerarray[type];
144 //array of primitives - do nothing
145 struct ArrayObject *ao=(struct ArrayObject *) vptr;
146 SENQUEUE((void *)ao->___objlocation___, *((void **)&ao->___objlocation___));
147 } else if (((INTPTR)pointer)==1) {
149 struct ArrayObject *ao=(struct ArrayObject *) vptr;
150 int length=ao->___length___;
152 SENQUEUE((void *)ao->___objlocation___, *((void **)&ao->___objlocation___));
154 int lowindex=ao->lowindex;
155 int highindex=ao->highindex;
157 for(j=lowindex; j<=highindex; j++) {
158 unsigned int lockval;
159 GETLOCKVAL(lockval, ao, j);
160 if (lockval!=STMNONE) {
161 int lowi=(j<<INDEXSHIFT)/sizeof(void *);
162 int highi=lowi+(INDEXLENGTH/sizeof(void *));
163 for(i=lowi; i<highi; i++) {
165 for(i=0; i<length; i++) {
167 void *objptr=((void **)(((char *)&ao->___length___)+sizeof(int)))[i];
168 SENQUEUE(objptr, ((void **)(((char *)&ao->___length___)+sizeof(int)))[i]);
175 INTPTR size=pointer[0];
177 for(i=1; i<=size; i++) {
178 unsigned int offset=pointer[i];
179 void * objptr=*((void **)(((char *)vptr)+offset));
180 SENQUEUE(objptr, *((void **)(((char *)vptr)+offset)));
186 index = (((unsigned INTPTR)key) & mask) >>4;
190 // Insert into the new table
192 tmp->key = curr->key;
193 tmp->val = curr->val;
196 } else if (isfirst) {
197 chashlistnode_t *newnode;
198 if ((*cstr)->num<NUMCLIST) {
199 newnode=&(*cstr)->array[(*cstr)->num];
203 cliststruct_t *tcl=calloc(1,sizeof(cliststruct_t));
206 newnode=&tcl->array[0];
209 newnode->key = curr->key;
210 newnode->val = curr->val;
211 newnode->next = tmp->next;
212 newnode->lnext=newlist;
218 curr->next=tmp->next;
233 if ((head==tail)&&(tailindex==headindex))
239 #if defined(STM)||defined(THREADS)||defined(MLP)
241 __thread char * memorybase=NULL;
242 __thread char * memorytop=NULL;
250 head=tail=malloc(sizeof(struct pointerblock));
256 taghead=malloc(sizeof(struct pointerblock));
263 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
265 pthread_mutex_lock(&gclistlock);
267 if ((listcount+1)==threadcount) {
268 break; /* Have all other threads stopped */
270 pthread_cond_wait(&gccond, &gclistlock);
277 for(i=0; i<MAXSTATS; i++)
284 litem.tc_size=c_size;
285 litem.tc_table=&c_table;
286 litem.tc_list=&c_list;
287 litem.tc_structs=&c_structs;
288 litem.objlist=newobjs;
290 litem.lockedlist=lockedobjs;
293 #if defined(STM)||defined(THREADS)||defined(MLP)
295 struct listitem *litem=pthread_getspecific(litemkey);
296 litem->base=((char **)pthread_getspecific(memorybasekey));
298 litem.base=&memorybase;
303 void searchglobalroots() {
304 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
307 struct garbagelist * stackptr=(struct garbagelist *)global_defs_p;
308 for(i=0; i<stackptr->size; i++) {
309 void * orig=stackptr->array[i];
310 ENQUEUE(orig, stackptr->array[i]);
316 void searchstack(struct garbagelist *stackptr) {
317 while(stackptr!=NULL) {
319 for(i=0; i<stackptr->size; i++) {
320 void * orig=stackptr->array[i];
321 ENQUEUE(orig, stackptr->array[i]);
323 stackptr=stackptr->next;
328 void searchjnitable(struct jnireferences *jniptr) {
329 while(jniptr!=NULL) {
332 for(i=0; i<jniptr->index; i++) {
333 ENQUEUE((ObjectPtr)jniptr->array[i].ref, *((ObjectPtr *)&jniptr->array[i].ref));
341 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
342 void searchthreadroots(struct garbagelist * stackptr) {
343 /* Check current stack */
344 struct listitem *listptr=list;
346 struct listitem *litem=pthread_getspecific(litemkey);
347 litem->stackptr=stackptr;
349 litem.stackptr=stackptr;
352 while(listptr!=NULL) {
353 searchstack(listptr->stackptr);
355 struct lockvector * lvector=listptr->lvector;
357 for(i=0; i<lvector->index; i++) {
358 ObjectPtr orig=lvector->locks[i].object;
359 ENQUEUE(orig, lvector->locks[i].object);
363 searchjnitable(*listptr->jnirefs);
366 if ((*listptr->tc_table)!=NULL) {
367 fixtable(listptr->tc_table, listptr->tc_list, listptr->tc_structs, listptr->tc_size);
368 fixobjlist(listptr->objlist);
370 fixobjlist(listptr->lockedlist);
374 #if defined(STM)||defined(THREADS)||defined(MLP)
375 *(listptr->base)=NULL;
378 // update forward list & memory queue for all running SESEs.
379 if (listptr->seseCommon!=NULL) {
380 updateForwardList(&((SESEcommon*)listptr->seseCommon)->forwardList,FALSE);
381 updateMemoryQueue((SESEcommon*)(listptr->seseCommon));
384 listptr=listptr->next;
389 void searchroots(struct garbagelist * stackptr) {
390 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
391 searchthreadroots(stackptr);
393 searchstack(stackptr);
396 ENQUEUE(___fcrevert___, ___fcrevert___);
407 void collect(struct garbagelist * stackptr) {
411 ptrstack.prev=stackptr;
412 stackptr=(struct garbagelist *) &ptrstack;
413 #if defined(STMARRAY)&&!defined(DUALVIEW)
414 arraystack.prev=stackptr;
415 stackptr=(struct garbagelist *) &arraystack;
419 searchroots(stackptr);
422 void * ptr=dequeue();
424 int type=((int *)cpy)[0];
425 unsigned INTPTR * pointer;
429 /* Nothing is inside */
434 pointer=pointerarray[type];
436 /* Array of primitives */
438 #if defined(DSTM)||defined(FASTCHECK)
439 struct ArrayObject *ao=(struct ArrayObject *) ptr;
440 struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
441 ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
442 ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
445 struct ArrayObject *ao=(struct ArrayObject *) ptr;
446 struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
447 SENQUEUE((void *)ao->___objlocation___, *((void **)&ao_cpy->___objlocation___));
449 } else if (((INTPTR)pointer)==1) {
450 /* Array of pointers */
451 struct ArrayObject *ao=(struct ArrayObject *) ptr;
452 struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
453 #if (defined(DSTM)||defined(FASTCHECK))
454 ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
455 ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
458 SENQUEUE((void *)ao->___objlocation___, *((void **)&ao_cpy->___objlocation___));
460 int length=ao->___length___;
462 for(i=0; i<length; i++) {
463 void *objptr=((void **)(((char *)&ao->___length___)+sizeof(int)))[i];
464 ENQUEUE(objptr, ((void **)(((char *)&ao_cpy->___length___)+sizeof(int)))[i]);
467 INTPTR size=pointer[0];
469 for(i=1; i<=size; i++) {
470 unsigned int offset=pointer[i];
471 void * objptr=*((void **)(((char *)ptr)+offset));
472 ENQUEUE(objptr, *((void **)(((char *)cpy)+offset)));
480 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
482 pthread_mutex_unlock(&gclistlock);
486 void * tomalloc(int size) {
487 void * ptr=to_heapptr;
494 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
495 void checkcollect(void * ptr) {
496 stopforgc((struct garbagelist *)ptr);
501 void checkcollect2(void * ptr) {
502 int ptrarray[]={1, (int)ptr, (int) revertlist};
503 stopforgc((struct garbagelist *)ptrarray);
505 revertlist=(ObjectPtr)ptrarray[2];
509 void stopforgc(struct garbagelist * ptr) {
511 //just append us to the list
513 ptr=(struct garbagelist *) &ptrstack;
514 #if defined(STMARRAY)&&!defined(DUALVIEW)
516 ptr=(struct garbagelist *) &arraystack;
521 #if defined(STM)||defined(THREADS)||defined(MLP)
522 litem.base=&memorybase;
525 litem.tc_size=c_size;
526 litem.tc_table=&c_table;
527 litem.tc_list=&c_list;
528 litem.tc_structs=&c_structs;
529 litem.objlist=newobjs;
531 litem.lockedlist=lockedobjs;
536 struct listitem *litem=pthread_getspecific(litemkey);
538 #if defined(STM)||defined(THREADS)||defined(MLP)
539 litem->base=pthread_getspecific(memorybasekey);
542 pthread_mutex_lock(&gclistlock);
544 if ((listcount+1)==threadcount) {
545 //only do wakeup if we are ready to GC
546 pthread_cond_signal(&gccond);
548 pthread_mutex_unlock(&gclistlock);
551 void restartaftergc() {
553 pthread_mutex_lock(&gclock); // Wait for GC
554 pthread_mutex_unlock(&gclock);
556 pthread_mutex_lock(&gclistlock);
558 pthread_mutex_unlock(&gclistlock);
561 struct listitem *litem=pthread_getspecific(litemkey);
567 #if defined(STM)||defined(THREADS)||defined(MLP)
568 #define MEMORYBLOCK 65536
569 void * helper(struct garbagelist *, int);
570 void * mygcmalloc(struct garbagelist * stackptr, int size) {
574 char * memorybase=*(char **)pthread_getspecific(memorybasekey);
575 char * memorytop=*(char **)pthread_getspecific(memorytopkey);
577 if (memorybase==NULL||size>(memorytop-memorybase)) {
578 int toallocate=(size>MEMORYBLOCK) ? size : MEMORYBLOCK;
579 memorybase=helper(stackptr, toallocate);
580 bzero(memorybase, toallocate);
581 memorytop=memorybase+toallocate;
583 char *retvalue=memorybase;
586 *(char **)pthread_getspecific(memorybasekey)=memorybase;
587 *(char **)pthread_getspecific(memorytopkey)=memorytop;
592 void * helper(struct garbagelist * stackptr, int size) {
594 void * mygcmalloc(struct garbagelist * stackptr, int size) {
597 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
598 while (pthread_mutex_trylock(&gclock)!=0) {
607 if (curr_heapptr>curr_heapgcpoint||curr_heapptr<curr_heapbase) {
608 if (curr_heapbase==0) {
609 /* Need to allocate base heap */
610 curr_heapbase=malloc(INITIALHEAPSIZE);
611 if (curr_heapbase==NULL) {
612 printf("malloc failed. Garbage colletcor couldn't get enough memory. Try changing heap size.\n");
615 #if defined(STM)||defined(THREADS)||defined(MLP)
617 bzero(curr_heapbase, INITIALHEAPSIZE);
619 curr_heaptop=curr_heapbase+INITIALHEAPSIZE;
620 curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(INITIALHEAPSIZE);
621 curr_heapptr=curr_heapbase+size;
623 to_heapbase=malloc(INITIALHEAPSIZE);
624 if (to_heapbase==NULL) {
625 printf("malloc failed. Garbage collector couldn't get enough memory. Try changing heap size.\n");
629 to_heaptop=to_heapbase+INITIALHEAPSIZE;
630 to_heapptr=to_heapbase;
632 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
633 pthread_mutex_unlock(&gclock);
638 /* Grow the to heap if necessary */
640 INTPTR curr_heapsize=curr_heaptop-curr_heapbase;
641 INTPTR to_heapsize=to_heaptop-to_heapbase;
642 INTPTR last_heapsize=0;
644 last_heapsize=HEAPSIZE(lastgcsize, size);
645 if ((last_heapsize&7)!=0)
646 last_heapsize+=(8-(last_heapsize%8));
648 if (curr_heapsize>last_heapsize)
649 last_heapsize=curr_heapsize;
650 if (last_heapsize>to_heapsize) {
652 to_heapbase=malloc(last_heapsize);
653 if (to_heapbase==NULL) {
654 printf("Error Allocating enough memory\n");
657 to_heaptop=to_heapbase+last_heapsize;
658 to_heapptr=to_heapbase;
662 /* Do our collection */
665 /* Update stat on previous gc size */
666 lastgcsize=(to_heapptr-to_heapbase)+size;
669 printf("Garbage collected: Old bytes: %u\n", curr_heapptr-curr_heapbase);
670 printf("New space: %u\n", to_heapptr-to_heapbase);
671 printf("Total space: %u\n", to_heaptop-to_heapbase);
674 for(i=0; i<MAXSTATS; i++) {
675 if (garbagearray[i]!=0)
676 printf("Type=%d Size=%u\n", i, garbagearray[i]);
680 /* Flip to/curr heaps */
682 void * tmp=to_heapbase;
683 to_heapbase=curr_heapbase;
687 to_heaptop=curr_heaptop;
691 curr_heapptr=to_heapptr+size;
692 curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(curr_heaptop-curr_heapbase);
693 to_heapptr=to_heapbase;
695 /* Not enough room :(, redo gc */
696 if (curr_heapptr>curr_heapgcpoint) {
697 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
698 pthread_mutex_unlock(&gclock);
700 return mygcmalloc(stackptr, size);
703 bzero(tmp, curr_heaptop-tmp);
704 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
705 pthread_mutex_unlock(&gclock);
710 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
711 pthread_mutex_unlock(&gclock);
717 int gc_createcopy(void * orig, void ** copy_ptr) {
722 int type=((int *)orig)[0];
724 *copy_ptr=((void **)orig)[1];
727 if (type<NUMCLASSES) {
728 /* We have a normal object */
730 int size=classsize[type]+sizeof(objheader_t);
731 void *newobj=tomalloc(size);
732 memcpy(newobj,((char *) orig)-sizeof(objheader_t), size);
733 newobj=((char *)newobj)+sizeof(objheader_t);
735 int size=classsize[type];
736 void *newobj=tomalloc(size);
737 memcpy(newobj, orig, size);
740 garbagearray[type]+=size;
743 ((void **)orig)[1]=newobj;
747 /* We have an array */
748 struct ArrayObject *ao=(struct ArrayObject *)orig;
749 int elementsize=classsize[type];
750 int length=ao->___length___;
753 int basesize=length*elementsize;
754 basesize=(basesize+LOWMASK)&HIGHMASK;
755 int versionspace=sizeof(int)*2*(basesize>>INDEXSHIFT);
756 int size=sizeof(struct ArrayObject)+basesize+sizeof(objheader_t)+versionspace;
757 void *newobj=tomalloc(size);
758 memcpy(newobj, ((char*)orig)-sizeof(objheader_t)-versionspace, size);
759 newobj=((char *)newobj)+sizeof(objheader_t)+versionspace;
761 int size=sizeof(struct ArrayObject)+length*elementsize+sizeof(objheader_t);
762 void *newobj=tomalloc(size);
763 memcpy(newobj, ((char*)orig)-sizeof(objheader_t), size);
764 newobj=((char *)newobj)+sizeof(objheader_t);
767 int size=sizeof(struct ArrayObject)+length*elementsize;
768 void *newobj=tomalloc(size);
769 memcpy(newobj, orig, size);
772 garbagearray[type]+=size;
775 ((void **)orig)[1]=newobj;
782 int within(void *ptr) { //debug function
783 if(ptr>curr_heapptr || ptr<curr_heapbase) {
784 __asm__ __volatile__ ("int $3"); // breakpoint