3 #include "structdefs.h"
5 #include "SimpleHash.h"
7 #include "GenericHashtable.h"
9 #if defined(THREADS) || defined(DSTM) || defined(STM)
25 #define INITIALHEAPSIZE 32*1024*1024
26 #define GCPOINT(x) ((int)((x)*0.9))
27 /* This define takes in how full the heap is initially and returns a new heap size to use */
28 #define HEAPSIZE(x,y) (((int)((x)/0.6))+y)
31 extern struct genhashtable * activetasks;
33 extern struct parameterwrapper * objectqueues[NUMCLASSES];
35 extern struct genhashtable * failedtasks;
36 extern struct taskparamdescriptor *currtpd;
37 extern struct ctable *forward;
38 extern struct ctable *reverse;
39 extern struct RuntimeHash *fdtoobject;
42 #if defined(THREADS) || defined(DSTM) || defined(STM)
44 struct listitem * list=NULL;
48 //Need to check if pointers are transaction pointers
49 //this also catches the special flag value of 1 for local copies
51 #define ENQUEUE(orig, dst) \
52 if ((!(((unsigned int)orig)&0x1))) { \
53 if (orig>=curr_heapbase&&orig<curr_heaptop) { \
55 if (gc_createcopy(orig,©)) \
61 #define ENQUEUE(orig, dst) \
62 if ((!(((unsigned int)orig)&0x1))) { \
63 if (orig>=curr_heapbase&&orig<curr_heaptop) { \
65 if (gc_createcopy(orig,©)) \
70 #elif defined(FASTCHECK)
71 #define ENQUEUE(orig, dst) \
72 if (((unsigned int)orig)!=1) { \
74 if (gc_createcopy(orig,©)) \
78 #define ENQUEUE(orig, dst) \
80 if (gc_createcopy(orig,©)) \
87 struct pointerblock *next;
90 void * curr_heapbase=0;
91 void * curr_heapptr=0;
92 void * curr_heapgcpoint=0;
93 void * curr_heaptop=0;
100 struct pointerblock *head=NULL;
102 struct pointerblock *tail=NULL;
104 struct pointerblock *spare=NULL;
106 void enqueue(void *ptr) {
107 if (headindex==NUMPTRS) {
108 struct pointerblock * tmp;
113 tmp=malloc(sizeof(struct pointerblock));
118 head->ptrs[headindex++]=ptr;
122 if (tailindex==NUMPTRS) {
123 struct pointerblock *tmp=tail;
131 return tail->ptrs[tailindex++];
135 if ((head==tail)&&(tailindex==headindex))
141 struct pointerblock *taghead=NULL;
144 void enqueuetag(struct ___TagDescriptor___ *ptr) {
145 if (tagindex==NUMPTRS) {
146 struct pointerblock * tmp=malloc(sizeof(struct pointerblock));
151 taghead->ptrs[tagindex++]=ptr;
156 void collect(struct garbagelist * stackptr) {
157 #if defined(THREADS)||defined(DSTM)||defined(STM)
159 pthread_mutex_lock(&gclistlock);
161 if ((listcount+1)==threadcount) {
162 break; /* Have all other threads stopped */
164 pthread_cond_wait(&gccond, &gclistlock);
171 head=tail=malloc(sizeof(struct pointerblock));
177 taghead=malloc(sizeof(struct pointerblock));
182 /* Check current stack */
183 #if defined(THREADS)||defined(DSTM)||defined(STM)
185 struct listitem *listptr=list;
189 while(stackptr!=NULL) {
191 for(i=0; i<stackptr->size; i++) {
192 void * orig=stackptr->array[i];
193 ENQUEUE(orig, stackptr->array[i]);
195 stackptr=stackptr->next;
197 #if defined(THREADS)||defined(DSTM)||defined(STM)
198 /* Go to next thread */
200 void * orig=listptr->locklist;
201 ENQUEUE(orig, listptr->locklist);
202 stackptr=listptr->stackptr;
203 listptr=listptr->next;
211 ENQUEUE(___fcrevert___, ___fcrevert___);
216 /* Update objectsets */
218 for(i=0; i<NUMCLASSES; i++) {
219 #if !defined(MULTICORE)
220 struct parameterwrapper * p=objectqueues[i];
222 struct ObjectHash * set=p->objectset;
223 struct ObjectNode * ptr=set->listhead;
225 void *orig=(void *)ptr->key;
226 ENQUEUE(orig, *((void **)(&ptr->key)));
229 ObjectHashrehash(set); /* Rehash the table */
238 struct cnode * ptr=forward->listhead;
240 void * orig=(void *)ptr->key;
241 ENQUEUE(orig, *((void **)(&ptr->key)));
244 crehash(forward); /* Rehash the table */
248 struct cnode * ptr=reverse->listhead;
250 void *orig=(void *)ptr->val;
251 ENQUEUE(orig, *((void**)(&ptr->val)));
258 struct RuntimeNode * ptr=fdtoobject->listhead;
260 void *orig=(void *)ptr->data;
261 ENQUEUE(orig, *((void**)(&ptr->data)));
267 /* Update current task descriptor */
269 for(i=0; i<currtpd->numParameters; i++) {
270 void *orig=currtpd->parameterArray[i];
271 ENQUEUE(orig, currtpd->parameterArray[i]);
276 /* Update active tasks */
278 struct genpointerlist * ptr=activetasks->list;
280 struct taskparamdescriptor *tpd=ptr->src;
282 for(i=0; i<tpd->numParameters; i++) {
283 void * orig=tpd->parameterArray[i];
284 ENQUEUE(orig, tpd->parameterArray[i]);
288 genrehash(activetasks);
291 /* Update failed tasks */
293 struct genpointerlist * ptr=failedtasks->list;
295 struct taskparamdescriptor *tpd=ptr->src;
297 for(i=0; i<tpd->numParameters; i++) {
298 void * orig=tpd->parameterArray[i];
299 ENQUEUE(orig, tpd->parameterArray[i]);
303 genrehash(failedtasks);
308 void * ptr=dequeue();
309 void *cpy=((void **)ptr)[1];
310 int type=((int *)cpy)[0];
311 unsigned int * pointer;
315 /* Nothing is inside */
320 pointer=pointerarray[type];
322 /* Array of primitives */
324 #if defined(DSTM)||defined(FASTCHECK)
325 struct ArrayObject *ao=(struct ArrayObject *) ptr;
326 struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
327 ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
328 ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
330 } else if (((int)pointer)==1) {
331 /* Array of pointers */
332 struct ArrayObject *ao=(struct ArrayObject *) ptr;
333 struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
334 #if (defined(DSTM)||defined(FASTCHECK))
335 ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
336 ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
338 int length=ao->___length___;
340 for(i=0; i<length; i++) {
341 void *objptr=((void **)(((char *)&ao->___length___)+sizeof(int)))[i];
342 ENQUEUE(objptr, ((void **)(((char *)&ao_cpy->___length___)+sizeof(int)))[i]);
347 for(i=1; i<=size; i++) {
348 unsigned int offset=pointer[i];
349 void * objptr=*((void **)(((int)ptr)+offset));
350 ENQUEUE(objptr, *((void **)(((int)cpy)+offset)));
358 #if defined(THREADS)||defined(DSTM)
360 pthread_mutex_unlock(&gclistlock);
365 /* Fix up the references from tags. This can't be done earlier,
366 because we don't want tags to keep objects alive */
368 while(taghead!=NULL) {
370 struct pointerblock *tmp=taghead->next;
371 for(i=0; i<tagindex; i++) {
372 struct ___TagDescriptor___ *tagd=taghead->ptrs[i];
373 struct ___Object___ *obj=tagd->flagptr;
374 struct ___TagDescriptor___ *copy=((struct ___TagDescriptor___**)tagd)[1];
376 /* Zero object case */
377 } else if (obj->type==-1) {
378 /* Single object case */
379 copy->flagptr=((struct ___Object___**)obj)[1];
380 } else if (obj->type==OBJECTARRAYTYPE) {
382 struct ArrayObject *ao=(struct ArrayObject *) obj;
386 struct ArrayObject *aonew;
388 /* Count live objects */
389 for(j=0; j<ao->___cachedCode___; j++) {
390 struct ___Object___ * tobj=ARRAYGET(ao, struct ___Object___ *, j);
395 livecount=((livecount-1)/OBJECTARRAYINTERVAL+1)*OBJECTARRAYINTERVAL;
396 aonew=(struct ArrayObject *) tomalloc(sizeof(struct ArrayObject)+sizeof(struct ___Object___*)*livecount);
397 memcpy(aonew, ao, sizeof(struct ArrayObject));
398 aonew->type=OBJECTARRAYTYPE;
399 aonew->___length___=livecount;
401 for(j=0; j<ao->___cachedCode___; j++) {
402 struct ___Object___ * tobj=ARRAYGET(ao, struct ___Object___ *, j);
403 if (tobj->type==-1) {
404 struct ___Object___ * tobjcpy=((struct ___Object___**)tobj)[1];
405 ARRAYSET(aonew, struct ___Object___*, k++,tobjcpy);
408 aonew->___cachedCode___=k;
409 for(; k<livecount; k++) {
410 ARRAYSET(aonew, struct ___Object___*, k, NULL);
413 /* No object live anymore */
424 void * tomalloc(int size) {
425 void * ptr=to_heapptr;
432 #if defined(THREADS)||defined(DSTM)||defined(STM)
433 void checkcollect(void * ptr) {
434 struct listitem * tmp=stopforgc((struct garbagelist *)ptr);
435 pthread_mutex_lock(&gclock); // Wait for GC
437 pthread_mutex_unlock(&gclock);
441 void checkcollect2(void * ptr) {
442 int ptrarray[]={1, (int)ptr, (int) revertlist};
443 struct listitem * tmp=stopforgc((struct garbagelist *)ptrarray);
444 pthread_mutex_lock(&gclock); // Wait for GC
446 pthread_mutex_unlock(&gclock);
447 revertlist=(struct ___Object___*)ptrarray[2];
452 struct listitem * stopforgc(struct garbagelist * ptr) {
453 struct listitem * litem=malloc(sizeof(struct listitem));
456 litem->locklist=pthread_getspecific(threadlocks);
459 litem->tc_size=c_size;
460 litem->tc_mask=c_mask;
461 litem->tc_table=&c_table;
464 pthread_mutex_lock(&gclistlock);
470 pthread_cond_signal(&gccond);
471 pthread_mutex_unlock(&gclistlock);
475 void restartaftergc(struct listitem * litem) {
476 pthread_mutex_lock(&gclistlock);
477 pthread_setspecific(threadlocks, litem->locklist);
478 if (litem->prev==NULL) {
481 litem->prev->next=litem->next;
483 if (litem->next!=NULL) {
484 litem->next->prev=litem->prev;
487 pthread_mutex_unlock(&gclistlock);
492 void * mygcmalloc(struct garbagelist * stackptr, int size) {
494 #if defined(THREADS)||defined(DSTM)||defined(STM)
495 if (pthread_mutex_trylock(&gclock)!=0) {
496 struct listitem *tmp=stopforgc(stackptr);
497 pthread_mutex_lock(&gclock);
505 if (curr_heapptr>curr_heapgcpoint) {
506 if (curr_heapbase==0) {
507 /* Need to allocate base heap */
508 curr_heapbase=malloc(INITIALHEAPSIZE);
509 bzero(curr_heapbase, INITIALHEAPSIZE);
510 curr_heaptop=curr_heapbase+INITIALHEAPSIZE;
511 curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(INITIALHEAPSIZE);
512 curr_heapptr=curr_heapbase+size;
514 to_heapbase=malloc(INITIALHEAPSIZE);
515 to_heaptop=to_heapbase+INITIALHEAPSIZE;
516 to_heapptr=to_heapbase;
518 #if defined(THREADS)||defined(DSTM)||defined(STM)
519 pthread_mutex_unlock(&gclock);
524 /* Grow the to heap if necessary */
526 int curr_heapsize=curr_heaptop-curr_heapbase;
527 int to_heapsize=to_heaptop-to_heapbase;
530 last_heapsize=HEAPSIZE(lastgcsize, size);
531 if ((last_heapsize&7)!=0)
532 last_heapsize+=(8-(last_heapsize%8));
534 if (curr_heapsize>last_heapsize)
535 last_heapsize=curr_heapsize;
536 if (last_heapsize>to_heapsize) {
538 to_heapbase=malloc(last_heapsize);
539 if (to_heapbase==NULL) {
540 printf("Error Allocating enough memory\n");
543 to_heaptop=to_heapbase+last_heapsize;
544 to_heapptr=to_heapbase;
548 /* Do our collection */
551 /* Update stat on previous gc size */
552 lastgcsize=(to_heapptr-to_heapbase)+size;
554 /* Flip to/curr heaps */
556 void * tmp=to_heapbase;
557 to_heapbase=curr_heapbase;
561 to_heaptop=curr_heaptop;
565 curr_heapptr=to_heapptr+size;
566 curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(curr_heaptop-curr_heapbase);
567 to_heapptr=to_heapbase;
569 /* Not enough room :(, redo gc */
570 if (curr_heapptr>curr_heapgcpoint) {
571 #if defined(THREADS)||defined(DSTM)||defined(STM)
572 pthread_mutex_unlock(&gclock);
574 return mygcmalloc(stackptr, size);
577 bzero(tmp, curr_heaptop-tmp);
578 #if defined(THREADS)||defined(DSTM)||defined(STM)
579 pthread_mutex_unlock(&gclock);
584 #if defined(THREADS)||defined(DSTM)||defined(STM)
585 pthread_mutex_unlock(&gclock);
592 int gc_createcopy(void * orig, void ** copy_ptr) {
597 int type=((int *)orig)[0];
599 *copy_ptr=((void **)orig)[1];
602 if (type<NUMCLASSES) {
603 /* We have a normal object */
604 int size=classsize[type];
605 void *newobj=tomalloc(size);
606 memcpy(newobj, orig, size);
608 ((void **)orig)[1]=newobj;
612 /* We have an array */
613 struct ArrayObject *ao=(struct ArrayObject *)orig;
614 int elementsize=classsize[type];
615 int length=ao->___length___;
616 int size=sizeof(struct ArrayObject)+length*elementsize;
617 void *newobj=tomalloc(size);
618 memcpy(newobj, orig, size);
620 ((void **)orig)[1]=newobj;