3 #include "structdefs.h"
5 #include "SimpleHash.h"
6 #include "GenericHashtable.h"
8 #if defined(THREADS) || defined(DSTM)
21 #define INITIALHEAPSIZE 10*1024
22 #define GCPOINT(x) ((int)((x)*0.9))
23 /* This define takes in how full the heap is initially and returns a new heap size to use */
24 #define HEAPSIZE(x,y) (((int)((x)/0.6))+y)
27 extern struct genhashtable * activetasks;
29 extern struct parameterwrapper * objectqueues[NUMCLASSES];
31 extern struct genhashtable * failedtasks;
32 extern struct taskparamdescriptor *currtpd;
33 extern struct RuntimeHash *forward;
34 extern struct RuntimeHash *reverse;
35 extern struct RuntimeHash *fdtoobject;
38 #if defined(THREADS) || defined(DSTM)
40 struct listitem * list=NULL;
44 //Need to check if pointers are transaction pointers
46 #define ENQUEUE(orig, dst) \
47 if ((!(((unsigned int)orig)&0x1))) { \
48 if (orig>=curr_heapbase&&orig<curr_heaptop) { \
50 if (gc_createcopy(orig,©)) \
56 #define ENQUEUE(orig, dst) \
58 if (gc_createcopy(orig,©)) \
65 struct pointerblock *next;
68 void * curr_heapbase=0;
69 void * curr_heapptr=0;
70 void * curr_heapgcpoint=0;
71 void * curr_heaptop=0;
78 struct pointerblock *head=NULL;
80 struct pointerblock *tail=NULL;
82 struct pointerblock *spare=NULL;
84 void enqueue(void *ptr) {
85 if (headindex==NUMPTRS) {
86 struct pointerblock * tmp;
91 tmp=malloc(sizeof(struct pointerblock));
96 head->ptrs[headindex++]=ptr;
100 if (tailindex==NUMPTRS) {
101 struct pointerblock *tmp=tail;
109 return tail->ptrs[tailindex++];
113 if ((head==tail)&&(tailindex==headindex))
119 struct pointerblock *taghead=NULL;
122 void enqueuetag(struct ___TagDescriptor___ *ptr) {
123 if (tagindex==NUMPTRS) {
124 struct pointerblock * tmp=malloc(sizeof(struct pointerblock));
129 taghead->ptrs[tagindex++]=ptr;
134 void collect(struct garbagelist * stackptr) {
135 #if defined(THREADS)||defined(DSTM)
137 pthread_mutex_lock(&gclistlock);
139 if ((listcount+1)==threadcount) {
140 break; /* Have all other threads stopped */
142 pthread_cond_wait(&gccond, &gclistlock);
149 head=tail=malloc(sizeof(struct pointerblock));
155 taghead=malloc(sizeof(struct pointerblock));
160 /* Check current stack */
161 #if defined(THREADS)||defined(DSTM)
163 struct listitem *listptr=list;
167 while(stackptr!=NULL) {
169 for(i=0; i<stackptr->size; i++) {
170 void * orig=stackptr->array[i];
171 ENQUEUE(orig, stackptr->array[i]);
173 stackptr=stackptr->next;
175 #if defined(THREADS)||defined(DSTM)
176 /* Go to next thread */
178 void * orig=listptr->locklist;
179 ENQUEUE(orig, listptr->locklist);
180 stackptr=listptr->stackptr;
181 listptr=listptr->next;
190 /* Update objectsets */
192 for(i=0; i<NUMCLASSES; i++) {
195 struct parameterwrapper * p=objectqueues[i];
197 struct ObjectHash * set=p->objectset;
198 struct ObjectNode * ptr=set->listhead;
200 void *orig=(void *)ptr->key;
201 ENQUEUE(orig, *((void **)(&ptr->key)));
204 ObjectHashrehash(set); /* Rehash the table */
212 struct RuntimeNode * ptr=forward->listhead;
214 void * orig=(void *)ptr->key;
215 ENQUEUE(orig, *((void **)(&ptr->key)));
218 RuntimeHashrehash(forward); /* Rehash the table */
222 struct RuntimeNode * ptr=reverse->listhead;
224 void *orig=(void *)ptr->data;
225 ENQUEUE(orig, *((void**)(&ptr->data)));
231 struct RuntimeNode * ptr=fdtoobject->listhead;
233 void *orig=(void *)ptr->data;
234 ENQUEUE(orig, *((void**)(&ptr->data)));
240 /* Update current task descriptor */
242 for(i=0; i<currtpd->numParameters; i++) {
243 void *orig=currtpd->parameterArray[i];
244 ENQUEUE(orig, currtpd->parameterArray[i]);
249 /* Update active tasks */
251 struct genpointerlist * ptr=activetasks->list;
253 struct taskparamdescriptor *tpd=ptr->src;
255 for(i=0; i<tpd->numParameters; i++) {
256 void * orig=tpd->parameterArray[i];
257 ENQUEUE(orig, tpd->parameterArray[i]);
261 genrehash(activetasks);
264 /* Update failed tasks */
266 struct genpointerlist * ptr=failedtasks->list;
268 struct taskparamdescriptor *tpd=ptr->src;
270 for(i=0; i<tpd->numParameters; i++) {
271 void * orig=tpd->parameterArray[i];
272 ENQUEUE(orig, tpd->parameterArray[i]);
276 genrehash(failedtasks);
281 void * ptr=dequeue();
282 void *cpy=((void **)ptr)[1];
283 int type=((int *)cpy)[0];
284 unsigned int * pointer;
288 /* Nothing is inside */
293 pointer=pointerarray[type];
295 /* Array of primitives */
298 struct ArrayObject *ao=(struct ArrayObject *) ptr;
299 struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
300 ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
301 ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
303 } else if (((int)pointer)==1) {
304 /* Array of pointers */
305 struct ArrayObject *ao=(struct ArrayObject *) ptr;
306 struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
308 ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
309 ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
311 int length=ao->___length___;
313 for(i=0; i<length; i++) {
314 void *objptr=((void **)(((char *)&ao->___length___)+sizeof(int)))[i];
315 ENQUEUE(objptr, ((void **)(((char *)&ao_cpy->___length___)+sizeof(int)))[i]);
320 for(i=1; i<=size; i++) {
321 unsigned int offset=pointer[i];
322 void * objptr=*((void **)(((int)ptr)+offset));
323 ENQUEUE(objptr, *((void **)(((int)cpy)+offset)));
331 #if defined(THREADS)||defined(DSTM)
333 pthread_mutex_unlock(&gclistlock);
339 /* Fix up the references from tags. This can't be done earlier,
340 because we don't want tags to keep objects alive */
342 while(taghead!=NULL) {
344 struct pointerblock *tmp=taghead->next;
345 for(i=0; i<tagindex; i++) {
346 struct ___TagDescriptor___ *tagd=taghead->ptrs[i];
347 struct ___Object___ *obj=tagd->flagptr;
348 struct ___TagDescriptor___ *copy=((struct ___TagDescriptor___**)tagd)[1];
350 /* Zero object case */
351 } else if (obj->type==-1) {
352 /* Single object case */
353 copy->flagptr=((struct ___Object___**)obj)[1];
354 } else if (obj->type==OBJECTARRAYTYPE) {
356 struct ArrayObject *ao=(struct ArrayObject *) obj;
360 struct ArrayObject *aonew;
362 /* Count live objects */
363 for(j=0; j<ao->___cachedCode___; j++) {
364 struct ___Object___ * tobj=ARRAYGET(ao, struct ___Object___ *, j);
369 livecount=((livecount-1)/OBJECTARRAYINTERVAL+1)*OBJECTARRAYINTERVAL;
370 aonew=(struct ArrayObject *) tomalloc(sizeof(struct ArrayObject)+sizeof(struct ___Object___*)*livecount);
371 memcpy(aonew, ao, sizeof(struct ArrayObject));
372 aonew->type=OBJECTARRAYTYPE;
373 aonew->___length___=livecount;
375 for(j=0; j<ao->___cachedCode___; j++) {
376 struct ___Object___ * tobj=ARRAYGET(ao, struct ___Object___ *, j);
377 if (tobj->type==-1) {
378 struct ___Object___ * tobjcpy=((struct ___Object___**)tobj)[1];
379 ARRAYSET(aonew, struct ___Object___*, k++,tobjcpy);
382 aonew->___cachedCode___=k;
383 for(; k<livecount; k++) {
384 ARRAYSET(aonew, struct ___Object___*, k, NULL);
387 /* No object live anymore */
398 void * tomalloc(int size) {
399 void * ptr=to_heapptr;
406 #if defined(THREADS)||defined(DSTM)
407 void checkcollect(void * ptr) {
409 struct listitem * tmp=stopforgc((struct garbagelist *)ptr);
410 pthread_mutex_lock(&gclock); // Wait for GC
412 pthread_mutex_unlock(&gclock);
418 void checkcollect2(void * ptr, transrecord_t *trans) {
420 int ptrarray[]={1, (int)ptr, (int) trans->revertlist};
421 struct listitem * tmp=stopforgc((struct garbagelist *)ptrarray);
422 pthread_mutex_lock(&gclock); // Wait for GC
424 pthread_mutex_unlock(&gclock);
425 trans->revertlist=(struct ___Object___*)ptrarray[2];
431 struct listitem * stopforgc(struct garbagelist * ptr) {
432 struct listitem * litem=malloc(sizeof(struct listitem));
434 litem->locklist=pthread_getspecific(threadlocks);
436 pthread_mutex_lock(&gclistlock);
442 pthread_cond_signal(&gccond);
443 pthread_mutex_unlock(&gclistlock);
447 void restartaftergc(struct listitem * litem) {
448 pthread_mutex_lock(&gclistlock);
449 pthread_setspecific(threadlocks, litem->locklist);
450 if (litem->prev==NULL) {
453 litem->prev->next=litem->next;
455 if (litem->next!=NULL) {
456 litem->next->prev=litem->prev;
459 pthread_mutex_unlock(&gclistlock);
464 void * mygcmalloc(struct garbagelist * stackptr, int size) {
466 #if defined(THREADS)||defined(DSTM)
467 if (pthread_mutex_trylock(&gclock)!=0) {
468 struct listitem *tmp=stopforgc(stackptr);
469 pthread_mutex_lock(&gclock);
477 if (curr_heapptr>curr_heapgcpoint) {
478 if (curr_heapbase==0) {
479 /* Need to allocate base heap */
480 curr_heapbase=malloc(INITIALHEAPSIZE);
481 bzero(curr_heapbase, INITIALHEAPSIZE);
482 curr_heaptop=curr_heapbase+INITIALHEAPSIZE;
483 curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(INITIALHEAPSIZE);
484 curr_heapptr=curr_heapbase+size;
486 to_heapbase=malloc(INITIALHEAPSIZE);
487 to_heaptop=to_heapbase+INITIALHEAPSIZE;
488 to_heapptr=to_heapbase;
490 #if defined(THREADS)||defined(DSTM)
491 pthread_mutex_unlock(&gclock);
496 /* Grow the to heap if necessary */
498 int curr_heapsize=curr_heaptop-curr_heapbase;
499 int to_heapsize=to_heaptop-to_heapbase;
502 last_heapsize=HEAPSIZE(lastgcsize, size);
503 if ((last_heapsize%4)!=0)
504 last_heapsize+=(4-(last_heapsize%4));
506 if (curr_heapsize>last_heapsize)
507 last_heapsize=curr_heapsize;
508 if (last_heapsize>to_heapsize) {
510 to_heapbase=malloc(last_heapsize);
511 to_heaptop=to_heapbase+last_heapsize;
512 to_heapptr=to_heapbase;
516 /* Do our collection */
519 /* Update stat on previous gc size */
520 lastgcsize=(to_heapptr-to_heapbase)+size;
522 /* Flip to/curr heaps */
524 void * tmp=to_heapbase;
525 to_heapbase=curr_heapbase;
529 to_heaptop=curr_heaptop;
533 curr_heapptr=to_heapptr+size;
534 curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(curr_heaptop-curr_heapbase);
535 to_heapptr=to_heapbase;
537 /* Not enough room :(, redo gc */
538 if (curr_heapptr>curr_heapgcpoint) {
539 #if defined(THREADS)||defined(DSTM)
540 pthread_mutex_unlock(&gclock);
542 return mygcmalloc(stackptr, size);
545 bzero(tmp, curr_heaptop-tmp);
546 #if defined(THREADS)||defined(DSTM)
547 pthread_mutex_unlock(&gclock);
552 #if defined(THREADS)||defined(DSTM)
553 pthread_mutex_unlock(&gclock);
560 int gc_createcopy(void * orig, void ** copy_ptr) {
565 int type=((int *)orig)[0];
567 *copy_ptr=((void **)orig)[1];
570 if (type<NUMCLASSES) {
571 /* We have a normal object */
572 int size=classsize[type];
573 void *newobj=tomalloc(size);
574 memcpy(newobj, orig, size);
576 ((void **)orig)[1]=newobj;
580 /* We have an array */
581 struct ArrayObject *ao=(struct ArrayObject *)orig;
582 int elementsize=classsize[type];
583 int length=ao->___length___;
584 int size=sizeof(struct ArrayObject)+length*elementsize;
585 void *newobj=tomalloc(size);
586 memcpy(newobj, orig, size);
588 ((void **)orig)[1]=newobj;