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