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