3 #include "structdefs.h"
5 #include "SimpleHash.h"
7 #include "GenericHashtable.h"
9 #if defined(THREADS) || defined(DSTM)
22 #define INITIALHEAPSIZE 8192*1024
23 #define GCPOINT(x) ((int)((x)*0.9))
24 /* This define takes in how full the heap is initially and returns a new heap size to use */
25 #define HEAPSIZE(x,y) (((int)((x)/0.6))+y)
28 extern struct genhashtable * activetasks;
30 extern struct parameterwrapper * objectqueues[NUMCLASSES];
32 extern struct genhashtable * failedtasks;
33 extern struct taskparamdescriptor *currtpd;
34 extern struct ctable *forward;
35 extern struct ctable *reverse;
36 extern struct RuntimeHash *fdtoobject;
39 #if defined(THREADS) || defined(DSTM)
41 struct listitem * list=NULL;
45 //Need to check if pointers are transaction pointers
46 //this also catches the special flag value of 1 for local copies
48 #define ENQUEUE(orig, dst) \
49 if ((!(((unsigned int)orig)&0x1))) { \
50 if (orig>=curr_heapbase&&orig<curr_heaptop) { \
52 if (gc_createcopy(orig,©)) \
58 #define ENQUEUE(orig, dst) \
60 if (gc_createcopy(orig,©)) \
67 struct pointerblock *next;
70 void * curr_heapbase=0;
71 void * curr_heapptr=0;
72 void * curr_heapgcpoint=0;
73 void * curr_heaptop=0;
80 struct pointerblock *head=NULL;
82 struct pointerblock *tail=NULL;
84 struct pointerblock *spare=NULL;
86 void enqueue(void *ptr) {
87 if (headindex==NUMPTRS) {
88 struct pointerblock * tmp;
93 tmp=malloc(sizeof(struct pointerblock));
98 head->ptrs[headindex++]=ptr;
102 if (tailindex==NUMPTRS) {
103 struct pointerblock *tmp=tail;
111 return tail->ptrs[tailindex++];
115 if ((head==tail)&&(tailindex==headindex))
121 struct pointerblock *taghead=NULL;
124 void enqueuetag(struct ___TagDescriptor___ *ptr) {
125 if (tagindex==NUMPTRS) {
126 struct pointerblock * tmp=malloc(sizeof(struct pointerblock));
131 taghead->ptrs[tagindex++]=ptr;
136 void collect(struct garbagelist * stackptr) {
137 #if defined(THREADS)||defined(DSTM)
139 pthread_mutex_lock(&gclistlock);
141 if ((listcount+1)==threadcount) {
142 break; /* Have all other threads stopped */
144 pthread_cond_wait(&gccond, &gclistlock);
151 head=tail=malloc(sizeof(struct pointerblock));
157 taghead=malloc(sizeof(struct pointerblock));
162 /* Check current stack */
163 #if defined(THREADS)||defined(DSTM)
165 struct listitem *listptr=list;
169 while(stackptr!=NULL) {
171 for(i=0; i<stackptr->size; i++) {
172 void * orig=stackptr->array[i];
173 ENQUEUE(orig, stackptr->array[i]);
175 stackptr=stackptr->next;
177 #if defined(THREADS)||defined(DSTM)
178 /* Go to next thread */
180 void * orig=listptr->locklist;
181 ENQUEUE(orig, listptr->locklist);
182 stackptr=listptr->stackptr;
183 listptr=listptr->next;
192 /* Update objectsets */
194 for(i=0; i<NUMCLASSES; i++) {
197 struct parameterwrapper * p=objectqueues[i];
199 struct ObjectHash * set=p->objectset;
200 struct ObjectNode * ptr=set->listhead;
202 void *orig=(void *)ptr->key;
203 ENQUEUE(orig, *((void **)(&ptr->key)));
206 ObjectHashrehash(set); /* Rehash the table */
214 struct cnode * ptr=forward->listhead;
216 void * orig=(void *)ptr->key;
217 ENQUEUE(orig, *((void **)(&ptr->key)));
220 crehash(forward); /* Rehash the table */
224 struct cnode * ptr=reverse->listhead;
226 void *orig=(void *)ptr->val;
227 ENQUEUE(orig, *((void**)(&ptr->val)));
233 struct RuntimeNode * ptr=fdtoobject->listhead;
235 void *orig=(void *)ptr->data;
236 ENQUEUE(orig, *((void**)(&ptr->data)));
242 /* Update current task descriptor */
244 for(i=0; i<currtpd->numParameters; i++) {
245 void *orig=currtpd->parameterArray[i];
246 ENQUEUE(orig, currtpd->parameterArray[i]);
251 /* Update active tasks */
253 struct genpointerlist * ptr=activetasks->list;
255 struct taskparamdescriptor *tpd=ptr->src;
257 for(i=0; i<tpd->numParameters; i++) {
258 void * orig=tpd->parameterArray[i];
259 ENQUEUE(orig, tpd->parameterArray[i]);
263 genrehash(activetasks);
266 /* Update failed tasks */
268 struct genpointerlist * ptr=failedtasks->list;
270 struct taskparamdescriptor *tpd=ptr->src;
272 for(i=0; i<tpd->numParameters; i++) {
273 void * orig=tpd->parameterArray[i];
274 ENQUEUE(orig, tpd->parameterArray[i]);
278 genrehash(failedtasks);
283 void * ptr=dequeue();
284 void *cpy=((void **)ptr)[1];
285 int type=((int *)cpy)[0];
286 unsigned int * pointer;
290 /* Nothing is inside */
295 pointer=pointerarray[type];
297 /* Array of primitives */
300 struct ArrayObject *ao=(struct ArrayObject *) ptr;
301 struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
302 ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
303 ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
305 } else if (((int)pointer)==1) {
306 /* Array of pointers */
307 struct ArrayObject *ao=(struct ArrayObject *) ptr;
308 struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
310 ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
311 ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
313 int length=ao->___length___;
315 for(i=0; i<length; i++) {
316 void *objptr=((void **)(((char *)&ao->___length___)+sizeof(int)))[i];
317 ENQUEUE(objptr, ((void **)(((char *)&ao_cpy->___length___)+sizeof(int)))[i]);
322 for(i=1; i<=size; i++) {
323 unsigned int offset=pointer[i];
324 void * objptr=*((void **)(((int)ptr)+offset));
325 ENQUEUE(objptr, *((void **)(((int)cpy)+offset)));
333 #if defined(THREADS)||defined(DSTM)
335 pthread_mutex_unlock(&gclistlock);
341 /* Fix up the references from tags. This can't be done earlier,
342 because we don't want tags to keep objects alive */
344 while(taghead!=NULL) {
346 struct pointerblock *tmp=taghead->next;
347 for(i=0; i<tagindex; i++) {
348 struct ___TagDescriptor___ *tagd=taghead->ptrs[i];
349 struct ___Object___ *obj=tagd->flagptr;
350 struct ___TagDescriptor___ *copy=((struct ___TagDescriptor___**)tagd)[1];
352 /* Zero object case */
353 } else if (obj->type==-1) {
354 /* Single object case */
355 copy->flagptr=((struct ___Object___**)obj)[1];
356 } else if (obj->type==OBJECTARRAYTYPE) {
358 struct ArrayObject *ao=(struct ArrayObject *) obj;
362 struct ArrayObject *aonew;
364 /* Count live objects */
365 for(j=0; j<ao->___cachedCode___; j++) {
366 struct ___Object___ * tobj=ARRAYGET(ao, struct ___Object___ *, j);
371 livecount=((livecount-1)/OBJECTARRAYINTERVAL+1)*OBJECTARRAYINTERVAL;
372 aonew=(struct ArrayObject *) tomalloc(sizeof(struct ArrayObject)+sizeof(struct ___Object___*)*livecount);
373 memcpy(aonew, ao, sizeof(struct ArrayObject));
374 aonew->type=OBJECTARRAYTYPE;
375 aonew->___length___=livecount;
377 for(j=0; j<ao->___cachedCode___; j++) {
378 struct ___Object___ * tobj=ARRAYGET(ao, struct ___Object___ *, j);
379 if (tobj->type==-1) {
380 struct ___Object___ * tobjcpy=((struct ___Object___**)tobj)[1];
381 ARRAYSET(aonew, struct ___Object___*, k++,tobjcpy);
384 aonew->___cachedCode___=k;
385 for(; k<livecount; k++) {
386 ARRAYSET(aonew, struct ___Object___*, k, NULL);
389 /* No object live anymore */
400 void * tomalloc(int size) {
401 void * ptr=to_heapptr;
408 #if defined(THREADS)||defined(DSTM)
409 void checkcollect(void * ptr) {
410 struct listitem * tmp=stopforgc((struct garbagelist *)ptr);
411 pthread_mutex_lock(&gclock); // Wait for GC
413 pthread_mutex_unlock(&gclock);
417 void checkcollect2(void * ptr, transrecord_t *trans) {
418 int ptrarray[]={1, (int)ptr, (int) trans->revertlist};
419 struct listitem * tmp=stopforgc((struct garbagelist *)ptrarray);
420 pthread_mutex_lock(&gclock); // Wait for GC
422 pthread_mutex_unlock(&gclock);
423 trans->revertlist=(struct ___Object___*)ptrarray[2];
428 struct listitem * stopforgc(struct garbagelist * ptr) {
429 struct listitem * litem=malloc(sizeof(struct listitem));
431 litem->locklist=pthread_getspecific(threadlocks);
433 pthread_mutex_lock(&gclistlock);
439 pthread_cond_signal(&gccond);
440 pthread_mutex_unlock(&gclistlock);
444 void restartaftergc(struct listitem * litem) {
445 pthread_mutex_lock(&gclistlock);
446 pthread_setspecific(threadlocks, litem->locklist);
447 if (litem->prev==NULL) {
450 litem->prev->next=litem->next;
452 if (litem->next!=NULL) {
453 litem->next->prev=litem->prev;
456 pthread_mutex_unlock(&gclistlock);
461 void * mygcmalloc(struct garbagelist * stackptr, int size) {
463 #if defined(THREADS)||defined(DSTM)
464 if (pthread_mutex_trylock(&gclock)!=0) {
465 struct listitem *tmp=stopforgc(stackptr);
466 pthread_mutex_lock(&gclock);
474 if (curr_heapptr>curr_heapgcpoint) {
475 if (curr_heapbase==0) {
476 /* Need to allocate base heap */
477 curr_heapbase=malloc(INITIALHEAPSIZE);
478 bzero(curr_heapbase, INITIALHEAPSIZE);
479 curr_heaptop=curr_heapbase+INITIALHEAPSIZE;
480 curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(INITIALHEAPSIZE);
481 curr_heapptr=curr_heapbase+size;
483 to_heapbase=malloc(INITIALHEAPSIZE);
484 to_heaptop=to_heapbase+INITIALHEAPSIZE;
485 to_heapptr=to_heapbase;
487 #if defined(THREADS)||defined(DSTM)
488 pthread_mutex_unlock(&gclock);
493 /* Grow the to heap if necessary */
495 int curr_heapsize=curr_heaptop-curr_heapbase;
496 int to_heapsize=to_heaptop-to_heapbase;
499 last_heapsize=HEAPSIZE(lastgcsize, size);
500 if ((last_heapsize%4)!=0)
501 last_heapsize+=(4-(last_heapsize%4));
503 if (curr_heapsize>last_heapsize)
504 last_heapsize=curr_heapsize;
505 if (last_heapsize>to_heapsize) {
507 to_heapbase=malloc(last_heapsize);
508 if (to_heapbase==NULL) {
509 printf("Error Allocating enough memory\n");
512 to_heaptop=to_heapbase+last_heapsize;
513 to_heapptr=to_heapbase;
517 /* Do our collection */
520 /* Update stat on previous gc size */
521 lastgcsize=(to_heapptr-to_heapbase)+size;
523 /* Flip to/curr heaps */
525 void * tmp=to_heapbase;
526 to_heapbase=curr_heapbase;
530 to_heaptop=curr_heaptop;
534 curr_heapptr=to_heapptr+size;
535 curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(curr_heaptop-curr_heapbase);
536 to_heapptr=to_heapbase;
538 /* Not enough room :(, redo gc */
539 if (curr_heapptr>curr_heapgcpoint) {
540 #if defined(THREADS)||defined(DSTM)
541 pthread_mutex_unlock(&gclock);
543 return mygcmalloc(stackptr, size);
546 bzero(tmp, curr_heaptop-tmp);
547 #if defined(THREADS)||defined(DSTM)
548 pthread_mutex_unlock(&gclock);
553 #if defined(THREADS)||defined(DSTM)
554 pthread_mutex_unlock(&gclock);
561 int gc_createcopy(void * orig, void ** copy_ptr) {
566 int type=((int *)orig)[0];
568 *copy_ptr=((void **)orig)[1];
571 if (type<NUMCLASSES) {
572 /* We have a normal object */
573 int size=classsize[type];
574 void *newobj=tomalloc(size);
575 memcpy(newobj, orig, size);
577 ((void **)orig)[1]=newobj;
581 /* We have an array */
582 struct ArrayObject *ao=(struct ArrayObject *)orig;
583 int elementsize=classsize[type];
584 int length=ao->___length___;
585 int size=sizeof(struct ArrayObject)+length*elementsize;
586 void *newobj=tomalloc(size);
587 memcpy(newobj, orig, size);
589 ((void **)orig)[1]=newobj;