3 #include "structdefs.h"
5 #include "SimpleHash.h"
6 #include "GenericHashtable.h"
18 #define INITIALHEAPSIZE 10*1024
19 #define GCPOINT(x) ((int)((x)*0.9))
20 /* This define takes in how full the heap is initially and returns a new heap size to use */
21 #define HEAPSIZE(x,y) (((int)((x)/0.6))+y)
24 extern struct genhashtable * activetasks;
25 extern struct parameterwrapper * objectqueues[NUMCLASSES];
26 extern struct genhashtable * failedtasks;
27 extern struct taskparamdescriptor *currtpd;
28 extern struct RuntimeHash *forward;
29 extern struct RuntimeHash *reverse;
30 extern struct RuntimeHash *fdtoobject;
35 struct listitem * list=NULL;
41 struct pointerblock *next;
44 struct pointerblock *head=NULL;
46 struct pointerblock *tail=NULL;
48 struct pointerblock *spare=NULL;
50 void enqueue(void *ptr) {
51 if (headindex==NUMPTRS) {
52 struct pointerblock * tmp;
57 tmp=malloc(sizeof(struct pointerblock));
62 head->ptrs[headindex++]=ptr;
66 if (tailindex==NUMPTRS) {
67 struct pointerblock *tmp=tail;
75 return tail->ptrs[tailindex++];
79 if ((head==tail)&&(tailindex==headindex))
85 struct pointerblock *taghead=NULL;
88 void enqueuetag(struct ___TagDescriptor___ *ptr) {
89 if (tagindex==NUMPTRS) {
90 struct pointerblock * tmp=malloc(sizeof(struct pointerblock));
95 taghead->ptrs[tagindex++]=ptr;
100 void collect(struct garbagelist * stackptr) {
103 pthread_mutex_lock(&gclistlock);
105 if ((listcount+1)==threadcount) {
106 break; /* Have all other threads stopped */
108 pthread_cond_wait(&gccond, &gclistlock);
115 head=tail=malloc(sizeof(struct pointerblock));
121 taghead=malloc(sizeof(struct pointerblock));
126 /* Check current stack */
129 struct listitem *listptr=list;
133 while(stackptr!=NULL) {
135 for(i=0;i<stackptr->size;i++) {
136 void * orig=stackptr->array[i];
138 if (gc_createcopy(orig,©))
140 stackptr->array[i]=copy;
142 stackptr=stackptr->next;
145 /* Go to next thread */
147 void * orig=listptr->locklist;
149 if (gc_createcopy(orig,©))
151 listptr->locklist=copy;
152 stackptr=listptr->stackptr;
153 listptr=listptr->next;
162 /* Update objectsets */
164 for(i=0;i<NUMCLASSES;i++) {
165 struct parameterwrapper * p=objectqueues[i];
167 struct RuntimeHash * set=p->objectset;
168 struct RuntimeNode * ptr=set->listhead;
170 void *orig=(void *)ptr->key;
172 if (gc_createcopy(orig, ©))
178 RuntimeHashrehash(set); /* Rehash the table */
185 struct RuntimeNode * ptr=forward->listhead;
187 void * orig=(void *)ptr->key;
189 if (gc_createcopy(orig, ©))
195 RuntimeHashrehash(forward); /* Rehash the table */
199 struct RuntimeNode * ptr=reverse->listhead;
201 void *orig=(void *)ptr->data;
203 if (gc_createcopy(orig, ©))
212 struct RuntimeNode * ptr=fdtoobject->listhead;
214 void *orig=(void *)ptr->data;
216 if (gc_createcopy(orig, ©))
225 /* Update current task descriptor */
227 for(i=0;i<currtpd->numParameters;i++) {
228 void *orig=currtpd->parameterArray[i];
230 if (gc_createcopy(orig, ©))
232 currtpd->parameterArray[i]=copy;
237 /* Update active tasks */
239 struct genpointerlist * ptr=activetasks->list;
241 struct taskparamdescriptor *tpd=ptr->src;
243 for(i=0;i<tpd->numParameters;i++) {
244 void * orig=tpd->parameterArray[i];
246 if (gc_createcopy(orig, ©))
248 tpd->parameterArray[i]=copy;
252 genrehash(activetasks);
255 /* Update failed tasks */
257 struct genpointerlist * ptr=failedtasks->list;
259 struct taskparamdescriptor *tpd=ptr->src;
261 for(i=0;i<tpd->numParameters;i++) {
262 void * orig=tpd->parameterArray[i];
264 if (gc_createcopy(orig, ©))
266 tpd->parameterArray[i]=copy;
270 genrehash(failedtasks);
275 void * ptr=dequeue();
276 void *cpy=((void **)ptr)[1];
277 int type=((int *)cpy)[0];
282 /* Nothing is inside */
287 pointer=pointerarray[type];
289 /* Array of primitives */
291 } else if (((int)pointer)==1) {
292 /* Array of pointers */
293 struct ArrayObject *ao=(struct ArrayObject *) ptr;
294 struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
295 int length=ao->___length___;
297 for(i=0;i<length;i++) {
298 void *objptr=((void **)(((char *)& ao->___length___)+sizeof(int)))[i];
300 if (gc_createcopy(objptr, ©))
302 ((void **)(((char *)& ao_cpy->___length___)+sizeof(int)))[i]=copy;
307 for(i=1;i<=size;i++) {
308 int offset=pointer[i];
309 void * objptr=*((void **)(((int)ptr)+offset));
311 if (gc_createcopy(objptr, ©))
313 *((void **) (((int)cpy)+offset))=copy;
323 pthread_mutex_unlock(&gclistlock);
329 while(taghead!=NULL) {
331 struct pointerblock *tmp=taghead->next;
332 for(i=0;i<tagindex;i++) {
333 struct ___TagDescriptor___ *tagd=taghead->ptrs[i];
334 struct ___Object___ *obj=tagd->flagptr;
335 struct ___TagDescriptor___ *copy=((struct ___TagDescriptor___**)tagd)[1];
337 /* Single object case */
338 copy->flagptr=((struct ___Object___**)obj)[1];
339 } else if (obj->type==OBJECTARRAYTYPE) {
341 struct ArrayObject *ao=(struct ArrayObject *) obj;
345 struct ArrayObject *aonew;
347 /* Count live objects */
348 for(j=0;j<ao->___cachedCode___;j++) {
349 struct ___Object___ * tobj=ARRAYGET(ao, struct ___Object___ *, j);
354 livecount=((livecount-1)/OBJECTARRAYINTERVAL+1)*OBJECTARRAYINTERVAL;
355 aonew=(struct ArrayObject *) tomalloc(sizeof(struct ArrayObject)+sizeof(struct ___Object___*)*livecount);
356 aonew->type=OBJECTARRAYTYPE;
357 aonew->___length___=livecount;
359 for(j=0;j<ao->___cachedCode___;j++) {
360 struct ___Object___ * tobj=ARRAYGET(ao, struct ___Object___ *, j);
361 if (tobj->type==-1) {
362 struct ___Object___ * tobjcpy=((struct ___Object___**)tobj)[1];
363 ARRAYSET(aonew, struct ___Object___*, k++,tobjcpy);
366 aonew->___cachedCode___=k;
369 /* No object live anymore */
380 void * curr_heapbase=0;
381 void * curr_heapptr=0;
382 void * curr_heapgcpoint=0;
383 void * curr_heaptop=0;
385 void * to_heapbase=0;
390 void * tomalloc(int size) {
391 void * ptr=to_heapptr;
400 void checkcollect(void * ptr) {
402 struct listitem * tmp=stopforgc((struct garbagelist *)ptr);
403 pthread_mutex_lock(&gclock); // Wait for GC
405 pthread_mutex_unlock(&gclock);
410 struct listitem * stopforgc(struct garbagelist * ptr) {
411 struct listitem * litem=malloc(sizeof(struct listitem));
413 litem->locklist=pthread_getspecific(threadlocks);
415 pthread_mutex_lock(&gclistlock);
421 pthread_cond_signal(&gccond);
422 pthread_mutex_unlock(&gclistlock);
426 void restartaftergc(struct listitem * litem) {
427 pthread_mutex_lock(&gclistlock);
428 pthread_setspecific(threadlocks, litem->locklist);
429 if (litem->prev==NULL) {
432 litem->prev->next=litem->next;
434 if (litem->next!=NULL) {
435 litem->next->prev=litem->prev;
438 pthread_mutex_unlock(&gclistlock);
443 void * mygcmalloc(struct garbagelist * stackptr, int size) {
446 if (pthread_mutex_trylock(&gclock)!=0) {
447 struct listitem *tmp=stopforgc(stackptr);
448 pthread_mutex_lock(&gclock);
456 if (curr_heapptr>curr_heapgcpoint) {
457 if (curr_heapbase==0) {
458 /* Need to allocate base heap */
459 curr_heapbase=malloc(INITIALHEAPSIZE);
460 bzero(curr_heapbase, INITIALHEAPSIZE);
461 curr_heaptop=curr_heapbase+INITIALHEAPSIZE;
462 curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(INITIALHEAPSIZE);
463 curr_heapptr=curr_heapbase+size;
465 to_heapbase=malloc(INITIALHEAPSIZE);
466 to_heaptop=to_heapbase+INITIALHEAPSIZE;
467 to_heapptr=to_heapbase;
470 pthread_mutex_unlock(&gclock);
475 /* Grow the to heap if necessary */
477 int curr_heapsize=curr_heaptop-curr_heapbase;
478 int to_heapsize=to_heaptop-to_heapbase;
481 last_heapsize=HEAPSIZE(lastgcsize, size);
482 if ((last_heapsize%4)!=0)
483 last_heapsize+=(4-(last_heapsize%4));
485 if (curr_heapsize>last_heapsize)
486 last_heapsize=curr_heapsize;
487 if (last_heapsize>to_heapsize) {
489 to_heapbase=malloc(last_heapsize);
490 to_heaptop=to_heapbase+last_heapsize;
491 to_heapptr=to_heapbase;
495 /* Do our collection */
498 /* Update stat on previous gc size */
499 lastgcsize=(to_heapptr-to_heapbase)+size;
501 /* Flip to/curr heaps */
503 void * tmp=to_heapbase;
504 to_heapbase=curr_heapbase;
508 to_heaptop=curr_heaptop;
512 curr_heapptr=to_heapptr+size;
513 curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(curr_heaptop-curr_heapbase);
514 to_heapptr=to_heapbase;
516 /* Not enough room :(, redo gc */
517 if (curr_heapptr>curr_heapgcpoint) {
519 pthread_mutex_unlock(&gclock);
521 return mygcmalloc(stackptr, size);
524 bzero(tmp, curr_heaptop-tmp);
526 pthread_mutex_unlock(&gclock);
532 pthread_mutex_unlock(&gclock);
539 int gc_createcopy(void * orig, void ** copy_ptr) {
544 int type=((int *)orig)[0];
546 *copy_ptr=((void **)orig)[1];
548 } if (type<NUMCLASSES) {
549 /* We have a normal object */
550 int size=classsize[type];
551 void *newobj=tomalloc(size);
552 memcpy(newobj, orig, size);
554 ((void **)orig)[1]=newobj;
558 /* We have an array */
559 struct ArrayObject *ao=(struct ArrayObject *)orig;
560 int elementsize=classsize[type];
561 int length=ao->___length___;
562 int size=sizeof(struct ArrayObject)+length*elementsize;
563 void *newobj=tomalloc(size);
564 memcpy(newobj, orig, size);
566 ((void **)orig)[1]=newobj;