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