various bug fixes
[IRC.git] / Robust / src / Runtime / garbage.c
1 #include "garbage.h"
2 #include "runtime.h"
3 #include "structdefs.h"
4 #include "Queue.h"
5 #include "SimpleHash.h"
6 #include "chash.h"
7 #include "GenericHashtable.h"
8 #include <string.h>
9 #if defined(THREADS) || defined(DSTM) || defined(STM)
10 #include "thread.h"
11 #endif
12
13 #ifdef DMALLOC
14 #include "dmalloc.h"
15 #endif
16 #ifdef DSTM
17 #include "dstm.h"
18 #endif
19 #ifdef STM
20 #include "tm.h"
21 #endif
22
23 #define NUMPTRS 100
24
25 #define INITIALHEAPSIZE 128*1024*1024
26 #define GCPOINT(x) ((int)((x)*0.95))
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+y))*2
29
30 #ifdef TASK
31 extern struct genhashtable * activetasks;
32 #ifndef MULTICORE
33 extern struct parameterwrapper * objectqueues[NUMCLASSES];
34 #endif
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;
40 #endif
41
42 #if defined(THREADS) || defined(DSTM) || defined(STM)
43 int needtocollect=0;
44 struct listitem * list=NULL;
45 int listcount=0;
46 #ifndef MAC
47 __thread struct listitem litem;
48 #endif
49 #endif
50
51 //Need to check if pointers are transaction pointers
52 //this also catches the special flag value of 1 for local copies
53 #ifdef DSTM
54 #define ENQUEUE(orig, dst) \
55   if ((!(((unsigned int)orig)&0x1))) { \
56     if (orig>=curr_heapbase&&orig<curr_heaptop) { \
57       void *copy; \
58       if (gc_createcopy(orig,&copy)) \
59         enqueue(orig);\
60       dst=copy; \
61     } \
62   }
63 #elif defined(STM)
64 #define ENQUEUE(orig, dst) \
65   if (orig>=curr_heapbase&&orig<curr_heaptop) { \
66     void *copy; \
67     if (gc_createcopy(orig,&copy)) \
68       enqueue(orig);\
69     dst=copy; \
70   }
71 #define SENQUEUE(orig, dst) \
72   { \
73     void *copy; \
74     if (gc_createcopy(orig,&copy)) \
75       enqueue(orig);\
76     dst=copy; \
77   }
78 #elif defined(FASTCHECK)
79 #define ENQUEUE(orig, dst) \
80   if (((unsigned int)orig)!=1) { \
81     void *copy; \
82     if (gc_createcopy(orig,&copy)) \
83       enqueue(orig);\
84     dst=copy; }
85 #else
86 #define ENQUEUE(orig, dst) \
87   void *copy; \
88   if (gc_createcopy(orig,&copy)) \
89     enqueue(orig);\
90   dst=copy
91 #endif
92
93 struct pointerblock {
94   void * ptrs[NUMPTRS];
95   struct pointerblock *next;
96 };
97
98 void * curr_heapbase=0;
99 void * curr_heapptr=0;
100 void * curr_heapgcpoint=0;
101 void * curr_heaptop=0;
102
103 void * to_heapbase=0;
104 void * to_heapptr=0;
105 void * to_heaptop=0;
106 long lastgcsize=0;
107
108 struct pointerblock *head=NULL;
109 int headindex=0;
110 struct pointerblock *tail=NULL;
111 int tailindex=0;
112 struct pointerblock *spare=NULL;
113
114 void enqueue(void *ptr) {
115   if (headindex==NUMPTRS) {
116     struct pointerblock * tmp;
117     if (spare!=NULL) {
118       tmp=spare;
119       spare=NULL;
120     } else
121       tmp=malloc(sizeof(struct pointerblock));
122     head->next=tmp;
123     head=tmp;
124     headindex=0;
125   }
126   head->ptrs[headindex++]=ptr;
127 }
128
129 void * dequeue() {
130   if (tailindex==NUMPTRS) {
131     struct pointerblock *tmp=tail;
132     tail=tail->next;
133     tailindex=0;
134     if (spare!=NULL)
135       free(tmp);
136     else
137       spare=tmp;
138   }
139   return tail->ptrs[tailindex++];
140 }
141
142 #ifdef STM
143 void fixobjlist(struct objlist * ptr) {
144   while(ptr!=NULL) {
145     int i;
146     for(i=0;i<ptr->offset;i++) {
147       SENQUEUE(ptr->objs[i], ptr->objs[i]);
148     }
149     ptr=ptr->next;
150   }
151 }
152
153 void fixtable(chashlistnode_t ** tc_table, chashlistnode_t **tc_list, cliststruct_t **cstr, unsigned int tc_size) {
154   unsigned int mask=(tc_size<<4)-1;
155   chashlistnode_t *node=calloc(tc_size, sizeof(chashlistnode_t));
156   chashlistnode_t *ptr=*tc_table;
157   chashlistnode_t *curr;
158   unsigned int i;
159   unsigned int index;
160   int isfirst;
161   chashlistnode_t *newlist=NULL;
162   for(i=0;i<tc_size;i++) {
163     curr=&ptr[i];
164     isfirst=1;
165     do {                      //Inner loop to go through linked lists
166       void * key;
167       chashlistnode_t *tmp,*next;
168       
169       if ((key=(void *)curr->key) == 0) {             //Exit inner loop if there the first element is 0
170         break;                  //key = val =0 for element if not present within the hash table
171       }
172       SENQUEUE(key, key);
173       if (curr->val>=curr_heapbase&&curr->val<curr_heaptop) {
174         SENQUEUE(curr->val, curr->val);
175       } else {
176         //rewrite transaction cache entry
177         void *vptr=curr->val;
178         int type=((int *)vptr)[0];
179         unsigned INTPTR *pointer=pointerarray[type];
180         if (pointer==0) {
181           //array of primitives - do nothing
182           struct ArrayObject *ao=(struct ArrayObject *) vptr;
183           SENQUEUE((void *)ao->___objlocation___, *((void **)&ao->___objlocation___));
184         } else if (((INTPTR)pointer)==1) {
185           //array of pointers
186           struct ArrayObject *ao=(struct ArrayObject *) vptr;
187           int length=ao->___length___;
188           int i;
189           SENQUEUE((void *)ao->___objlocation___, *((void **)&ao->___objlocation___));
190           for(i=0; i<length; i++) {
191             void *objptr=((void **)(((char *)&ao->___length___)+sizeof(int)))[i];
192             SENQUEUE(objptr, ((void **)(((char *)&ao->___length___)+sizeof(int)))[i]);
193           }
194         } else {
195           INTPTR size=pointer[0];
196           int i;
197           for(i=1; i<=size; i++) {
198             unsigned int offset=pointer[i];
199             void * objptr=*((void **)(((char *)vptr)+offset));
200             SENQUEUE(objptr, *((void **)(((char *)vptr)+offset)));
201           }
202         }
203       }
204
205       next = curr->next;
206       index = (((unsigned INTPTR)key) & mask) >>4;
207
208       curr->key=key;
209       tmp=&node[index];
210       // Insert into the new table
211       if(tmp->key == 0) {
212         tmp->key = curr->key;
213         tmp->val = curr->val;
214         tmp->lnext=newlist;
215         newlist=tmp;
216       } else if (isfirst) {
217         chashlistnode_t *newnode;
218         if ((*cstr)->num<NUMCLIST) {
219           newnode=&(*cstr)->array[(*cstr)->num];
220           (*cstr)->num++;
221         } else {
222           //get new list
223           cliststruct_t *tcl=calloc(1,sizeof(cliststruct_t));
224           tcl->next=*cstr;
225           *cstr=tcl;
226           newnode=&tcl->array[0];
227           tcl->num=1;
228         }
229         newnode->key = curr->key;
230         newnode->val = curr->val;
231         newnode->next = tmp->next;
232         newnode->lnext=newlist;
233         newlist=newnode;
234         tmp->next=newnode;
235       } else {
236         curr->lnext=newlist;
237         newlist=curr;
238         curr->next=tmp->next;
239         tmp->next=curr;
240       }
241       isfirst = 0;
242       curr = next;
243     } while(curr!=NULL);
244   }
245   free(ptr);
246   (*tc_table)=node;
247   (*tc_list)=newlist;
248 }
249 #endif
250
251 int moreItems() {
252   if ((head==tail)&&(tailindex==headindex))
253     return 0;
254   return 1;
255 }
256
257 #ifdef TASK
258 struct pointerblock *taghead=NULL;
259 int tagindex=0;
260
261 void enqueuetag(struct ___TagDescriptor___ *ptr) {
262   if (tagindex==NUMPTRS) {
263     struct pointerblock * tmp=malloc(sizeof(struct pointerblock));
264     tmp->next=taghead;
265     taghead=tmp;
266     tagindex=0;
267   }
268   taghead->ptrs[tagindex++]=ptr;
269 }
270 #endif
271
272 #if defined(STM)||defined(THREADS)
273 __thread char * memorybase=NULL;
274 __thread char * memorytop=NULL;
275 #endif
276
277
278 void collect(struct garbagelist * stackptr) {
279 #if defined(THREADS)||defined(DSTM)||defined(STM)
280   needtocollect=1;
281   pthread_mutex_lock(&gclistlock);
282   while(1) {
283     if ((listcount+1)==threadcount) {
284       break; /* Have all other threads stopped */
285     }
286     pthread_cond_wait(&gccond, &gclistlock);
287   }
288 #endif
289
290   if (head==NULL) {
291     headindex=0;
292     tailindex=0;
293     head=tail=malloc(sizeof(struct pointerblock));
294   }
295
296 #ifdef TASK
297   if (taghead==NULL) {
298     tagindex=0;
299     taghead=malloc(sizeof(struct pointerblock));
300     taghead->next=NULL;
301   }
302 #endif
303
304 #ifdef STM
305   if (c_table!=NULL) {
306     fixtable(&c_table, &c_list, &c_structs, c_size);
307     fixobjlist(newobjs);
308 #ifdef STMSTATS
309     fixobjlist(lockedobjs);
310 #endif
311   }
312   memorybase=NULL;
313 #endif
314
315   /* Check current stack */
316 #if defined(THREADS)||defined(DSTM)||defined(STM)
317   {
318     struct listitem *listptr=list;
319     while(1) {
320 #endif
321
322   while(stackptr!=NULL) {
323     int i;
324     for(i=0; i<stackptr->size; i++) {
325       void * orig=stackptr->array[i];
326       ENQUEUE(orig, stackptr->array[i]);
327     }
328     stackptr=stackptr->next;
329   }
330 #if defined(THREADS)||defined(DSTM)||defined(STM)
331   /* Go to next thread */
332 #ifndef MAC
333   //skip over us
334   if (listptr==&litem) {
335     listptr=listptr->next;
336   }
337 #else
338  {
339   struct listitem *litem=pthread_getspecific(litemkey);
340   if (listptr==litem) {
341     listptr=listptr->next;
342   }
343  }
344 #endif
345
346   if (listptr!=NULL) {
347 #ifdef THREADS
348     void * orig=listptr->locklist;
349     ENQUEUE(orig, listptr->locklist);
350 #endif
351 #ifdef STM
352     if ((*listptr->tc_table)!=NULL) {
353       fixtable(listptr->tc_table, listptr->tc_list, listptr->tc_structs, listptr->tc_size);
354       fixobjlist(listptr->objlist);
355 #ifdef STMSTATS
356       fixobjlist(listptr->lockedlist);
357 #endif
358     }
359     *(listptr->base)=NULL;
360 #endif
361     stackptr=listptr->stackptr;
362     listptr=listptr->next;
363   } else
364     break;
365 }
366 }
367 #endif
368
369 #ifdef FASTCHECK
370   ENQUEUE(___fcrevert___, ___fcrevert___);
371 #endif
372
373 #ifdef TASK
374   {
375     /* Update objectsets */
376     int i;
377     for(i=0; i<NUMCLASSES; i++) {
378 #if !defined(MULTICORE)
379       struct parameterwrapper * p=objectqueues[i];
380       while(p!=NULL) {
381         struct ObjectHash * set=p->objectset;
382         struct ObjectNode * ptr=set->listhead;
383         while(ptr!=NULL) {
384           void *orig=(void *)ptr->key;
385           ENQUEUE(orig, *((void **)(&ptr->key)));
386           ptr=ptr->lnext;
387         }
388         ObjectHashrehash(set); /* Rehash the table */
389         p=p->next;
390       }
391 #endif
392     }
393   }
394
395 #ifndef FASTCHECK
396   if (forward!=NULL) {
397     struct cnode * ptr=forward->listhead;
398     while(ptr!=NULL) {
399       void * orig=(void *)ptr->key;
400       ENQUEUE(orig, *((void **)(&ptr->key)));
401       ptr=ptr->lnext;
402     }
403     crehash(forward); /* Rehash the table */
404   }
405
406   if (reverse!=NULL) {
407     struct cnode * ptr=reverse->listhead;
408     while(ptr!=NULL) {
409       void *orig=(void *)ptr->val;
410       ENQUEUE(orig, *((void**)(&ptr->val)));
411       ptr=ptr->lnext;
412     }
413   }
414 #endif
415
416   {
417     struct RuntimeNode * ptr=fdtoobject->listhead;
418     while(ptr!=NULL) {
419       void *orig=(void *)ptr->data;
420       ENQUEUE(orig, *((void**)(&ptr->data)));
421       ptr=ptr->lnext;
422     }
423   }
424
425   {
426     /* Update current task descriptor */
427     int i;
428     for(i=0; i<currtpd->numParameters; i++) {
429       void *orig=currtpd->parameterArray[i];
430       ENQUEUE(orig, currtpd->parameterArray[i]);
431     }
432
433   }
434
435   /* Update active tasks */
436   {
437     struct genpointerlist * ptr=activetasks->list;
438     while(ptr!=NULL) {
439       struct taskparamdescriptor *tpd=ptr->src;
440       int i;
441       for(i=0; i<tpd->numParameters; i++) {
442         void * orig=tpd->parameterArray[i];
443         ENQUEUE(orig, tpd->parameterArray[i]);
444       }
445       ptr=ptr->inext;
446     }
447     genrehash(activetasks);
448   }
449
450   /* Update failed tasks */
451   {
452     struct genpointerlist * ptr=failedtasks->list;
453     while(ptr!=NULL) {
454       struct taskparamdescriptor *tpd=ptr->src;
455       int i;
456       for(i=0; i<tpd->numParameters; i++) {
457         void * orig=tpd->parameterArray[i];
458         ENQUEUE(orig, tpd->parameterArray[i]);
459       }
460       ptr=ptr->inext;
461     }
462     genrehash(failedtasks);
463   }
464 #endif
465
466   while(moreItems()) {
467     void * ptr=dequeue();
468     void *cpy=((void **)ptr)[1];
469     int type=((int *)cpy)[0];
470     unsigned INTPTR * pointer;
471 #ifdef TASK
472     if(type==TAGTYPE) {
473       /* Enqueue Tag */
474       /* Nothing is inside */
475       enqueuetag(ptr);
476       continue;
477     }
478 #endif
479     pointer=pointerarray[type];
480     if (pointer==0) {
481       /* Array of primitives */
482       /* Do nothing */
483 #if defined(DSTM)||defined(FASTCHECK)
484       struct ArrayObject *ao=(struct ArrayObject *) ptr;
485       struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
486       ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
487       ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
488 #endif
489 #if defined(STM)
490       struct ArrayObject *ao=(struct ArrayObject *) ptr;
491       struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
492       SENQUEUE((void *)ao->___objlocation___, *((void **)&ao_cpy->___objlocation___));
493 #endif
494     } else if (((INTPTR)pointer)==1) {
495       /* Array of pointers */
496       struct ArrayObject *ao=(struct ArrayObject *) ptr;
497       struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
498 #if (defined(DSTM)||defined(FASTCHECK))
499       ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
500       ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
501 #endif
502 #if defined(STM)
503       SENQUEUE((void *)ao->___objlocation___, *((void **)&ao_cpy->___objlocation___));
504 #endif
505       int length=ao->___length___;
506       int i;
507       for(i=0; i<length; i++) {
508         void *objptr=((void **)(((char *)&ao->___length___)+sizeof(int)))[i];
509         ENQUEUE(objptr, ((void **)(((char *)&ao_cpy->___length___)+sizeof(int)))[i]);
510       }
511     } else {
512       INTPTR size=pointer[0];
513       int i;
514       for(i=1; i<=size; i++) {
515         unsigned int offset=pointer[i];
516         void * objptr=*((void **)(((char *)ptr)+offset));
517         ENQUEUE(objptr, *((void **)(((char *)cpy)+offset)));
518       }
519     }
520   }
521 #ifdef TASK
522   fixtags();
523 #endif
524
525 #if defined(THREADS)||defined(DSTM)||defined(STM)
526   needtocollect=0;
527   pthread_mutex_unlock(&gclistlock);
528 #endif
529 }
530
531 #ifdef TASK
532 /* Fix up the references from tags.  This can't be done earlier,
533    because we don't want tags to keep objects alive */
534 void fixtags() {
535   while(taghead!=NULL) {
536     int i;
537     struct pointerblock *tmp=taghead->next;
538     for(i=0; i<tagindex; i++) {
539       struct ___TagDescriptor___ *tagd=taghead->ptrs[i];
540       struct ___Object___ *obj=tagd->flagptr;
541       struct ___TagDescriptor___ *copy=((struct ___TagDescriptor___**)tagd)[1];
542       if (obj==NULL) {
543         /* Zero object case */
544       } else if (obj->type==-1) {
545         /* Single object case */
546         copy->flagptr=((struct ___Object___**)obj)[1];
547       } else if (obj->type==OBJECTARRAYTYPE) {
548         /* Array case */
549         struct ArrayObject *ao=(struct ArrayObject *) obj;
550         int livecount=0;
551         int j;
552         int k=0;
553         struct ArrayObject *aonew;
554
555         /* Count live objects */
556         for(j=0; j<ao->___cachedCode___; j++) {
557           struct ___Object___ * tobj=ARRAYGET(ao, struct ___Object___ *, j);
558           if (tobj->type==-1)
559             livecount++;
560         }
561
562         livecount=((livecount-1)/OBJECTARRAYINTERVAL+1)*OBJECTARRAYINTERVAL;
563         aonew=(struct ArrayObject *) tomalloc(sizeof(struct ArrayObject)+sizeof(struct ___Object___*)*livecount);
564         memcpy(aonew, ao, sizeof(struct ArrayObject));
565         aonew->type=OBJECTARRAYTYPE;
566         aonew->___length___=livecount;
567         copy->flagptr=aonew;
568         for(j=0; j<ao->___cachedCode___; j++) {
569           struct ___Object___ * tobj=ARRAYGET(ao, struct ___Object___ *, j);
570           if (tobj->type==-1) {
571             struct ___Object___ * tobjcpy=((struct ___Object___**)tobj)[1];
572             ARRAYSET(aonew, struct ___Object___*, k++,tobjcpy);
573           }
574         }
575         aonew->___cachedCode___=k;
576         for(; k<livecount; k++) {
577           ARRAYSET(aonew, struct ___Object___*, k, NULL);
578         }
579       } else {
580         /* No object live anymore */
581         copy->flagptr=NULL;
582       }
583     }
584     free(taghead);
585     taghead=tmp;
586     tagindex=NUMPTRS;
587   }
588 }
589 #endif
590
591 void * tomalloc(int size) {
592   void * ptr=to_heapptr;
593   if ((size&7)!=0)
594     size+=(8-(size%8));
595   to_heapptr+=size;
596   return ptr;
597 }
598
599 #if defined(THREADS)||defined(DSTM)||defined(STM)
600 void checkcollect(void * ptr) {
601   stopforgc((struct garbagelist *)ptr);
602   pthread_mutex_lock(&gclock); // Wait for GC
603   restartaftergc();
604   pthread_mutex_unlock(&gclock);
605 }
606
607 #ifdef DSTM
608 void checkcollect2(void * ptr) {
609   int ptrarray[]={1, (int)ptr, (int) revertlist};
610   stopforgc((struct garbagelist *)ptrarray);
611   pthread_mutex_lock(&gclock); // Wait for GC
612   restartaftergc();
613   pthread_mutex_unlock(&gclock);
614   revertlist=(struct ___Object___*)ptrarray[2];
615 }
616 #endif
617
618 void stopforgc(struct garbagelist * ptr) {
619 #ifndef MAC
620   litem.stackptr=ptr;
621 #ifdef THREADS
622   litem.locklist=pthread_getspecific(threadlocks);
623 #endif
624 #ifdef STM
625   litem.tc_size=c_size;
626   litem.tc_table=&c_table;
627   litem.tc_list=&c_list;
628   litem.tc_structs=&c_structs;
629   litem.objlist=newobjs;
630 #ifdef STMSTATS
631   litem.lockedlist=lockedobjs;
632 #endif
633   litem.base=&memorybase;
634 #endif
635 #else
636   //handle MAC
637   struct listitem *litem=pthread_getspecific(litemkey);
638   litem->stackptr=ptr;
639 #ifdef THREADS
640   litem->locklist=pthread_getspecific(threadlocks);
641 #endif
642 #endif
643   pthread_mutex_lock(&gclistlock);
644   listcount++;
645   if ((listcount+1)==threadcount) {
646     //only do wakeup if we are ready to GC
647     pthread_cond_signal(&gccond);
648   }
649   pthread_mutex_unlock(&gclistlock);
650 }
651
652 void restartaftergc() {
653   pthread_mutex_lock(&gclistlock);
654   listcount--;
655   pthread_mutex_unlock(&gclistlock);
656 }
657 #endif
658
659 #if defined(STM)||defined(THREADS)
660 #define MEMORYBLOCK 65536
661 void * helper(struct garbagelist *, int);
662 void * mygcmalloc(struct garbagelist * stackptr, int size) {
663   if ((size&7)!=0)
664     size=(size&~7)+8;
665   if (memorybase==NULL||(memorybase+size)>memorytop) {
666     int toallocate=(size>MEMORYBLOCK)?size:MEMORYBLOCK;
667     memorybase=helper(stackptr, toallocate);
668     memorytop=memorybase+toallocate;
669   }
670   char *retvalue=memorybase;
671   memorybase+=size;
672   return retvalue;
673 }
674
675 void * helper(struct garbagelist * stackptr, int size) {
676 #else
677 void * mygcmalloc(struct garbagelist * stackptr, int size) {
678 #endif
679   void *ptr;
680 #if defined(THREADS)||defined(DSTM)||defined(STM)
681   if (pthread_mutex_trylock(&gclock)!=0) {
682     stopforgc(stackptr);
683     pthread_mutex_lock(&gclock);
684     restartaftergc();
685   }
686 #endif
687   ptr=curr_heapptr;
688   if ((size&7)!=0)
689     size=(size&~7)+8;
690   curr_heapptr+=size;
691   if (curr_heapptr>curr_heapgcpoint) {
692     if (curr_heapbase==0) {
693       /* Need to allocate base heap */
694       curr_heapbase=malloc(INITIALHEAPSIZE);
695       if (curr_heapbase==NULL) {
696         printf("malloc failed\n");
697         exit(-1);
698       }
699       bzero(curr_heapbase, INITIALHEAPSIZE);
700       curr_heaptop=curr_heapbase+INITIALHEAPSIZE;
701       curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(INITIALHEAPSIZE);
702       curr_heapptr=curr_heapbase+size;
703
704       to_heapbase=malloc(INITIALHEAPSIZE);
705       if (to_heapbase==NULL) {
706         printf("malloc failed\n");
707         exit(-1);
708       }
709       to_heaptop=to_heapbase+INITIALHEAPSIZE;
710       to_heapptr=to_heapbase;
711       ptr=curr_heapbase;
712 #if defined(THREADS)||defined(DSTM)||defined(STM)
713       pthread_mutex_unlock(&gclock);
714 #endif
715       return ptr;
716     }
717
718     /* Grow the to heap if necessary */
719     {
720       int curr_heapsize=curr_heaptop-curr_heapbase;
721       int to_heapsize=to_heaptop-to_heapbase;
722       int last_heapsize=0;
723       if (lastgcsize>0) {
724         last_heapsize=HEAPSIZE(lastgcsize, size);
725         if ((last_heapsize&7)!=0)
726           last_heapsize+=(8-(last_heapsize%8));
727       }
728       if (curr_heapsize>last_heapsize)
729         last_heapsize=curr_heapsize;
730       if (last_heapsize>to_heapsize) {
731         free(to_heapbase);
732         to_heapbase=malloc(last_heapsize);
733         if (to_heapbase==NULL) {
734           printf("Error Allocating enough memory\n");
735           exit(-1);
736         }
737         to_heaptop=to_heapbase+last_heapsize;
738         to_heapptr=to_heapbase;
739       }
740     }
741
742     /* Do our collection */
743     collect(stackptr);
744
745     /* Update stat on previous gc size */
746     lastgcsize=(to_heapptr-to_heapbase)+size;
747
748 #ifdef GARBAGESTATS
749     printf("Garbage collected: Old bytes: %u\n", curr_heapptr-curr_heapbase);
750     printf("New space: %u\n", to_heapptr-to_heapbase);
751     printf("Total space: %u\n", to_heaptop-to_heapbase);
752 #endif
753     /* Flip to/curr heaps */
754     {
755       void * tmp=to_heapbase;
756       to_heapbase=curr_heapbase;
757       curr_heapbase=tmp;
758
759       tmp=to_heaptop;
760       to_heaptop=curr_heaptop;
761       curr_heaptop=tmp;
762
763       tmp=to_heapptr;
764       curr_heapptr=to_heapptr+size;
765       curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(curr_heaptop-curr_heapbase);
766       to_heapptr=to_heapbase;
767
768       /* Not enough room :(, redo gc */
769       if (curr_heapptr>curr_heapgcpoint) {
770 #if defined(THREADS)||defined(DSTM)||defined(STM)
771         pthread_mutex_unlock(&gclock);
772 #endif
773         return mygcmalloc(stackptr, size);
774       }
775
776       bzero(tmp, curr_heaptop-tmp);
777 #if defined(THREADS)||defined(DSTM)||defined(STM)
778       pthread_mutex_unlock(&gclock);
779 #endif
780       return tmp;
781     }
782   } else {
783 #if defined(THREADS)||defined(DSTM)||defined(STM)
784     pthread_mutex_unlock(&gclock);
785 #endif
786     return ptr;
787   }
788 }
789
790
791 int gc_createcopy(void * orig, void ** copy_ptr) {
792   if (orig==0) {
793     *copy_ptr=NULL;
794     return 0;
795   } else {
796     int type=((int *)orig)[0];
797     if (type==-1) {
798       *copy_ptr=((void **)orig)[1];
799       return 0;
800     }
801     if (type<NUMCLASSES) {
802       /* We have a normal object */
803 #ifdef STM
804       int size=classsize[type]+sizeof(objheader_t);
805       void *newobj=tomalloc(size);
806       memcpy(newobj,((char *) orig)-sizeof(objheader_t), size);
807       newobj=((char *)newobj)+sizeof(objheader_t);
808 #else
809       int size=classsize[type];
810       void *newobj=tomalloc(size);
811       memcpy(newobj, orig, size);
812 #endif
813       ((int *)orig)[0]=-1;
814       ((void **)orig)[1]=newobj;
815       *copy_ptr=newobj;
816       return 1;
817     } else {
818       /* We have an array */
819       struct ArrayObject *ao=(struct ArrayObject *)orig;
820       int elementsize=classsize[type];
821       int length=ao->___length___;
822 #ifdef STM
823       int size=sizeof(struct ArrayObject)+length*elementsize+sizeof(objheader_t);
824       void *newobj=tomalloc(size);
825       memcpy(newobj, ((char*)orig)-sizeof(objheader_t), size);
826       newobj=((char *)newobj)+sizeof(objheader_t);
827 #else
828       int size=sizeof(struct ArrayObject)+length*elementsize;
829       void *newobj=tomalloc(size);
830       memcpy(newobj, orig, size);
831 #endif
832
833       ((int *)orig)[0]=-1;
834       ((void **)orig)[1]=newobj;
835       *copy_ptr=newobj;
836       return 1;
837     }
838   }
839 }