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;
28 extern struct parameterwrapper * objectqueues[NUMCLASSES];
29 extern struct genhashtable * failedtasks;
30 extern struct taskparamdescriptor *currtpd;
31 extern struct RuntimeHash *forward;
32 extern struct RuntimeHash *reverse;
33 extern struct RuntimeHash *fdtoobject;
36 #if defined(THREADS) || defined(DSTM)
38 struct listitem * list=NULL;
42 //Need to check if pointers are transaction pointers
44 #define ENQUEUE(orig, dst) \
45 if ((!(((unsigned int)orig)&0x1))) {\
46 if (orig>=curr_heapbase&&orig<curr_heaptop) {\
48 if (gc_createcopy(orig,©))\
54 #define ENQUEUE(orig, dst) \
56 if (gc_createcopy(orig,©))\
63 struct pointerblock *next;
66 void * curr_heapbase=0;
67 void * curr_heapptr=0;
68 void * curr_heapgcpoint=0;
69 void * curr_heaptop=0;
76 struct pointerblock *head=NULL;
78 struct pointerblock *tail=NULL;
80 struct pointerblock *spare=NULL;
82 void enqueue(void *ptr) {
83 if (headindex==NUMPTRS) {
84 struct pointerblock * tmp;
89 tmp=malloc(sizeof(struct pointerblock));
94 head->ptrs[headindex++]=ptr;
98 if (tailindex==NUMPTRS) {
99 struct pointerblock *tmp=tail;
107 return tail->ptrs[tailindex++];
111 if ((head==tail)&&(tailindex==headindex))
117 struct pointerblock *taghead=NULL;
120 void enqueuetag(struct ___TagDescriptor___ *ptr) {
121 if (tagindex==NUMPTRS) {
122 struct pointerblock * tmp=malloc(sizeof(struct pointerblock));
127 taghead->ptrs[tagindex++]=ptr;
132 void collect(struct garbagelist * stackptr) {
133 #if defined(THREADS)||defined(DSTM)
135 pthread_mutex_lock(&gclistlock);
137 if ((listcount+1)==threadcount) {
138 break; /* Have all other threads stopped */
140 pthread_cond_wait(&gccond, &gclistlock);
147 head=tail=malloc(sizeof(struct pointerblock));
153 taghead=malloc(sizeof(struct pointerblock));
158 /* Check current stack */
159 #if defined(THREADS)||defined(DSTM)
161 struct listitem *listptr=list;
165 while(stackptr!=NULL) {
167 for(i=0;i<stackptr->size;i++) {
168 void * orig=stackptr->array[i];
169 ENQUEUE(orig, stackptr->array[i]);
171 stackptr=stackptr->next;
173 #if defined(THREADS)||defined(DSTM)
174 /* Go to next thread */
176 void * orig=listptr->locklist;
177 ENQUEUE(orig, listptr->locklist);
178 stackptr=listptr->stackptr;
179 listptr=listptr->next;
188 /* Update objectsets */
190 for(i=0;i<NUMCLASSES;i++) {
191 struct parameterwrapper * p=objectqueues[i];
193 struct ObjectHash * set=p->objectset;
194 struct ObjectNode * ptr=set->listhead;
196 void *orig=(void *)ptr->key;
197 ENQUEUE(orig, *((void **)(&ptr->key)));
200 ObjectHashrehash(set); /* Rehash the table */
207 struct RuntimeNode * ptr=forward->listhead;
209 void * orig=(void *)ptr->key;
210 ENQUEUE(orig, *((void **)(&ptr->key)));
213 RuntimeHashrehash(forward); /* Rehash the table */
217 struct RuntimeNode * ptr=reverse->listhead;
219 void *orig=(void *)ptr->data;
220 ENQUEUE(orig, *((void**)(&ptr->data)));
226 struct RuntimeNode * ptr=fdtoobject->listhead;
228 void *orig=(void *)ptr->data;
229 ENQUEUE(orig, *((void**)(&ptr->data)));
235 /* Update current task descriptor */
237 for(i=0;i<currtpd->numParameters;i++) {
238 void *orig=currtpd->parameterArray[i];
239 ENQUEUE(orig, currtpd->parameterArray[i]);
244 /* Update active tasks */
246 struct genpointerlist * ptr=activetasks->list;
248 struct taskparamdescriptor *tpd=ptr->src;
250 for(i=0;i<tpd->numParameters;i++) {
251 void * orig=tpd->parameterArray[i];
252 ENQUEUE(orig, tpd->parameterArray[i]);
256 genrehash(activetasks);
259 /* Update failed tasks */
261 struct genpointerlist * ptr=failedtasks->list;
263 struct taskparamdescriptor *tpd=ptr->src;
265 for(i=0;i<tpd->numParameters;i++) {
266 void * orig=tpd->parameterArray[i];
267 ENQUEUE(orig, tpd->parameterArray[i]);
271 genrehash(failedtasks);
276 void * ptr=dequeue();
277 void *cpy=((void **)ptr)[1];
278 int type=((int *)cpy)[0];
279 unsigned int * pointer;
283 /* Nothing is inside */
288 pointer=pointerarray[type];
290 /* Array of primitives */
293 struct ArrayObject *ao=(struct ArrayObject *) ptr;
294 struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
295 ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
296 ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
298 } else if (((int)pointer)==1) {
299 /* Array of pointers */
300 struct ArrayObject *ao=(struct ArrayObject *) ptr;
301 struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
303 ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
304 ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
306 int length=ao->___length___;
308 for(i=0;i<length;i++) {
309 void *objptr=((void **)(((char *)& ao->___length___)+sizeof(int)))[i];
310 ENQUEUE(objptr, ((void **)(((char *)& ao_cpy->___length___)+sizeof(int)))[i]);
315 for(i=1;i<=size;i++) {
316 unsigned int offset=pointer[i];
317 void * objptr=*((void **)(((int)ptr)+offset));
318 ENQUEUE(objptr, *((void **) (((int)cpy)+offset)));
326 #if defined(THREADS)||defined(DSTM)
328 pthread_mutex_unlock(&gclistlock);
334 /* Fix up the references from tags. This can't be done earlier,
335 because we don't want tags to keep objects alive */
337 while(taghead!=NULL) {
339 struct pointerblock *tmp=taghead->next;
340 for(i=0;i<tagindex;i++) {
341 struct ___TagDescriptor___ *tagd=taghead->ptrs[i];
342 struct ___Object___ *obj=tagd->flagptr;
343 struct ___TagDescriptor___ *copy=((struct ___TagDescriptor___**)tagd)[1];
345 /* Zero object case */
346 } else if (obj->type==-1) {
347 /* Single object case */
348 copy->flagptr=((struct ___Object___**)obj)[1];
349 } else if (obj->type==OBJECTARRAYTYPE) {
351 struct ArrayObject *ao=(struct ArrayObject *) obj;
355 struct ArrayObject *aonew;
357 /* Count live objects */
358 for(j=0;j<ao->___cachedCode___;j++) {
359 struct ___Object___ * tobj=ARRAYGET(ao, struct ___Object___ *, j);
364 livecount=((livecount-1)/OBJECTARRAYINTERVAL+1)*OBJECTARRAYINTERVAL;
365 aonew=(struct ArrayObject *) tomalloc(sizeof(struct ArrayObject)+sizeof(struct ___Object___*)*livecount);
366 memcpy(aonew, ao, sizeof(struct ArrayObject));
367 aonew->type=OBJECTARRAYTYPE;
368 aonew->___length___=livecount;
370 for(j=0;j<ao->___cachedCode___;j++) {
371 struct ___Object___ * tobj=ARRAYGET(ao, struct ___Object___ *, j);
372 if (tobj->type==-1) {
373 struct ___Object___ * tobjcpy=((struct ___Object___**)tobj)[1];
374 ARRAYSET(aonew, struct ___Object___*, k++,tobjcpy);
377 aonew->___cachedCode___=k;
378 for(;k<livecount;k++) {
379 ARRAYSET(aonew, struct ___Object___*, k, NULL);
382 /* No object live anymore */
393 void * tomalloc(int size) {
394 void * ptr=to_heapptr;
401 #if defined(THREADS)||defined(DSTM)
402 void checkcollect(void * ptr) {
404 struct listitem * tmp=stopforgc((struct garbagelist *)ptr);
405 pthread_mutex_lock(&gclock); // Wait for GC
407 pthread_mutex_unlock(&gclock);
413 void checkcollect2(void * ptr, transrecord_t *trans) {
415 int ptrarray[]={1, (int)ptr, (int) trans->revertlist};
416 struct listitem * tmp=stopforgc((struct garbagelist *)ptrarray);
417 pthread_mutex_lock(&gclock); // Wait for GC
419 pthread_mutex_unlock(&gclock);
420 trans->revertlist=(struct ___Object___*)ptrarray[2];
426 struct listitem * stopforgc(struct garbagelist * ptr) {
427 struct listitem * litem=malloc(sizeof(struct listitem));
429 litem->locklist=pthread_getspecific(threadlocks);
431 pthread_mutex_lock(&gclistlock);
437 pthread_cond_signal(&gccond);
438 pthread_mutex_unlock(&gclistlock);
442 void restartaftergc(struct listitem * litem) {
443 pthread_mutex_lock(&gclistlock);
444 pthread_setspecific(threadlocks, litem->locklist);
445 if (litem->prev==NULL) {
448 litem->prev->next=litem->next;
450 if (litem->next!=NULL) {
451 litem->next->prev=litem->prev;
454 pthread_mutex_unlock(&gclistlock);
459 void * mygcmalloc(struct garbagelist * stackptr, int size) {
461 #if defined(THREADS)||defined(DSTM)
462 if (pthread_mutex_trylock(&gclock)!=0) {
463 struct listitem *tmp=stopforgc(stackptr);
464 pthread_mutex_lock(&gclock);
472 if (curr_heapptr>curr_heapgcpoint) {
473 if (curr_heapbase==0) {
474 /* Need to allocate base heap */
475 curr_heapbase=malloc(INITIALHEAPSIZE);
476 bzero(curr_heapbase, INITIALHEAPSIZE);
477 curr_heaptop=curr_heapbase+INITIALHEAPSIZE;
478 curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(INITIALHEAPSIZE);
479 curr_heapptr=curr_heapbase+size;
481 to_heapbase=malloc(INITIALHEAPSIZE);
482 to_heaptop=to_heapbase+INITIALHEAPSIZE;
483 to_heapptr=to_heapbase;
485 #if defined(THREADS)||defined(DSTM)
486 pthread_mutex_unlock(&gclock);
491 /* Grow the to heap if necessary */
493 int curr_heapsize=curr_heaptop-curr_heapbase;
494 int to_heapsize=to_heaptop-to_heapbase;
497 last_heapsize=HEAPSIZE(lastgcsize, size);
498 if ((last_heapsize%4)!=0)
499 last_heapsize+=(4-(last_heapsize%4));
501 if (curr_heapsize>last_heapsize)
502 last_heapsize=curr_heapsize;
503 if (last_heapsize>to_heapsize) {
505 to_heapbase=malloc(last_heapsize);
506 to_heaptop=to_heapbase+last_heapsize;
507 to_heapptr=to_heapbase;
511 /* Do our collection */
514 /* Update stat on previous gc size */
515 lastgcsize=(to_heapptr-to_heapbase)+size;
517 /* Flip to/curr heaps */
519 void * tmp=to_heapbase;
520 to_heapbase=curr_heapbase;
524 to_heaptop=curr_heaptop;
528 curr_heapptr=to_heapptr+size;
529 curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(curr_heaptop-curr_heapbase);
530 to_heapptr=to_heapbase;
532 /* Not enough room :(, redo gc */
533 if (curr_heapptr>curr_heapgcpoint) {
534 #if defined(THREADS)||defined(DSTM)
535 pthread_mutex_unlock(&gclock);
537 return mygcmalloc(stackptr, size);
540 bzero(tmp, curr_heaptop-tmp);
541 #if defined(THREADS)||defined(DSTM)
542 pthread_mutex_unlock(&gclock);
547 #if defined(THREADS)||defined(DSTM)
548 pthread_mutex_unlock(&gclock);
555 int gc_createcopy(void * orig, void ** copy_ptr) {
560 int type=((int *)orig)[0];
562 *copy_ptr=((void **)orig)[1];
564 } if (type<NUMCLASSES) {
565 /* We have a normal object */
566 int size=classsize[type];
567 void *newobj=tomalloc(size);
568 memcpy(newobj, orig, size);
570 ((void **)orig)[1]=newobj;
574 /* We have an array */
575 struct ArrayObject *ao=(struct ArrayObject *)orig;
576 int elementsize=classsize[type];
577 int length=ao->___length___;
578 int size=sizeof(struct ArrayObject)+length*elementsize;
579 void *newobj=tomalloc(size);
580 memcpy(newobj, orig, size);
582 ((void **)orig)[1]=newobj;