change
[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 #endif
306
307 #ifdef GARBAGESTATS
308   {
309     int i;
310     for(i=0;i<MAXSTATS;i++)
311       garbagearray[i]=0;
312   }
313 #endif
314
315   if (head==NULL) {
316     headindex=0;
317     tailindex=0;
318     head=tail=malloc(sizeof(struct pointerblock));
319   }
320
321 #ifdef TASK
322   if (taghead==NULL) {
323     tagindex=0;
324     taghead=malloc(sizeof(struct pointerblock));
325     taghead->next=NULL;
326   }
327 #endif
328
329 #ifdef STM
330   if (c_table!=NULL) {
331     fixtable(&c_table, &c_list, &c_structs, c_size);
332     fixobjlist(newobjs);
333 #ifdef STMSTATS
334     fixobjlist(lockedobjs);
335 #endif
336   }
337   memorybase=NULL;
338 #endif
339
340   /* Check current stack */
341 #if defined(THREADS)||defined(DSTM)||defined(STM)
342   {
343     struct listitem *listptr=list;
344     while(1) {
345 #endif
346
347   while(stackptr!=NULL) {
348     int i;
349     for(i=0; i<stackptr->size; i++) {
350       void * orig=stackptr->array[i];
351       ENQUEUE(orig, stackptr->array[i]);
352     }
353     stackptr=stackptr->next;
354   }
355 #if defined(THREADS)||defined(DSTM)||defined(STM)
356   /* Go to next thread */
357 #ifndef MAC
358   //skip over us
359   if (listptr==&litem) {
360     listptr=listptr->next;
361   }
362 #else
363  {
364   struct listitem *litem=pthread_getspecific(litemkey);
365   if (listptr==litem) {
366     listptr=listptr->next;
367   }
368  }
369 #endif
370
371   if (listptr!=NULL) {
372 #ifdef THREADS
373     void * orig=listptr->locklist;
374     ENQUEUE(orig, listptr->locklist);
375 #endif
376 #ifdef STM
377     if ((*listptr->tc_table)!=NULL) {
378       fixtable(listptr->tc_table, listptr->tc_list, listptr->tc_structs, listptr->tc_size);
379       fixobjlist(listptr->objlist);
380 #ifdef STMSTATS
381       fixobjlist(listptr->lockedlist);
382 #endif
383     }
384     *(listptr->base)=NULL;
385 #endif
386     stackptr=listptr->stackptr;
387     listptr=listptr->next;
388   } else
389     break;
390 }
391 }
392 #endif
393
394 #ifdef FASTCHECK
395   ENQUEUE(___fcrevert___, ___fcrevert___);
396 #endif
397
398 #ifdef TASK
399   {
400     /* Update objectsets */
401     int i;
402     for(i=0; i<NUMCLASSES; i++) {
403 #if !defined(MULTICORE)
404       struct parameterwrapper * p=objectqueues[i];
405       while(p!=NULL) {
406         struct ObjectHash * set=p->objectset;
407         struct ObjectNode * ptr=set->listhead;
408         while(ptr!=NULL) {
409           void *orig=(void *)ptr->key;
410           ENQUEUE(orig, *((void **)(&ptr->key)));
411           ptr=ptr->lnext;
412         }
413         ObjectHashrehash(set); /* Rehash the table */
414         p=p->next;
415       }
416 #endif
417     }
418   }
419
420 #ifndef FASTCHECK
421   if (forward!=NULL) {
422     struct cnode * ptr=forward->listhead;
423     while(ptr!=NULL) {
424       void * orig=(void *)ptr->key;
425       ENQUEUE(orig, *((void **)(&ptr->key)));
426       ptr=ptr->lnext;
427     }
428     crehash(forward); /* Rehash the table */
429   }
430
431   if (reverse!=NULL) {
432     struct cnode * ptr=reverse->listhead;
433     while(ptr!=NULL) {
434       void *orig=(void *)ptr->val;
435       ENQUEUE(orig, *((void**)(&ptr->val)));
436       ptr=ptr->lnext;
437     }
438   }
439 #endif
440
441   {
442     struct RuntimeNode * ptr=fdtoobject->listhead;
443     while(ptr!=NULL) {
444       void *orig=(void *)ptr->data;
445       ENQUEUE(orig, *((void**)(&ptr->data)));
446       ptr=ptr->lnext;
447     }
448   }
449
450   {
451     /* Update current task descriptor */
452     int i;
453     for(i=0; i<currtpd->numParameters; i++) {
454       void *orig=currtpd->parameterArray[i];
455       ENQUEUE(orig, currtpd->parameterArray[i]);
456     }
457
458   }
459
460   /* Update active tasks */
461   {
462     struct genpointerlist * ptr=activetasks->list;
463     while(ptr!=NULL) {
464       struct taskparamdescriptor *tpd=ptr->src;
465       int i;
466       for(i=0; i<tpd->numParameters; i++) {
467         void * orig=tpd->parameterArray[i];
468         ENQUEUE(orig, tpd->parameterArray[i]);
469       }
470       ptr=ptr->inext;
471     }
472     genrehash(activetasks);
473   }
474
475   /* Update failed tasks */
476   {
477     struct genpointerlist * ptr=failedtasks->list;
478     while(ptr!=NULL) {
479       struct taskparamdescriptor *tpd=ptr->src;
480       int i;
481       for(i=0; i<tpd->numParameters; i++) {
482         void * orig=tpd->parameterArray[i];
483         ENQUEUE(orig, tpd->parameterArray[i]);
484       }
485       ptr=ptr->inext;
486     }
487     genrehash(failedtasks);
488   }
489 #endif
490
491   while(moreItems()) {
492     void * ptr=dequeue();
493     void *cpy=ptr;
494     int type=((int *)cpy)[0];
495     unsigned INTPTR * pointer;
496 #ifdef TASK
497     if(type==TAGTYPE) {
498       /* Enqueue Tag */
499       /* Nothing is inside */
500       enqueuetag(ptr);
501       continue;
502     }
503 #endif
504     pointer=pointerarray[type];
505     if (pointer==0) {
506       /* Array of primitives */
507       /* Do nothing */
508 #if defined(DSTM)||defined(FASTCHECK)
509       struct ArrayObject *ao=(struct ArrayObject *) ptr;
510       struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
511       ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
512       ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
513 #endif
514 #if defined(STM)
515       struct ArrayObject *ao=(struct ArrayObject *) ptr;
516       struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
517       SENQUEUE((void *)ao->___objlocation___, *((void **)&ao_cpy->___objlocation___));
518 #endif
519     } else if (((INTPTR)pointer)==1) {
520       /* Array of pointers */
521       struct ArrayObject *ao=(struct ArrayObject *) ptr;
522       struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
523 #if (defined(DSTM)||defined(FASTCHECK))
524       ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
525       ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
526 #endif
527 #if defined(STM)
528       SENQUEUE((void *)ao->___objlocation___, *((void **)&ao_cpy->___objlocation___));
529 #endif
530       int length=ao->___length___;
531       int i;
532       for(i=0; i<length; i++) {
533         void *objptr=((void **)(((char *)&ao->___length___)+sizeof(int)))[i];
534         ENQUEUE(objptr, ((void **)(((char *)&ao_cpy->___length___)+sizeof(int)))[i]);
535       }
536     } else {
537       INTPTR size=pointer[0];
538       int i;
539       for(i=1; i<=size; i++) {
540         unsigned int offset=pointer[i];
541         void * objptr=*((void **)(((char *)ptr)+offset));
542         ENQUEUE(objptr, *((void **)(((char *)cpy)+offset)));
543       }
544     }
545   }
546 #ifdef TASK
547   fixtags();
548 #endif
549
550 #if defined(THREADS)||defined(DSTM)||defined(STM)
551   needtocollect=0;
552   pthread_mutex_unlock(&gclistlock);
553 #endif
554 }
555
556 #ifdef TASK
557 /* Fix up the references from tags.  This can't be done earlier,
558    because we don't want tags to keep objects alive */
559 void fixtags() {
560   while(taghead!=NULL) {
561     int i;
562     struct pointerblock *tmp=taghead->next;
563     for(i=0; i<tagindex; i++) {
564       struct ___TagDescriptor___ *tagd=taghead->ptrs[i];
565       struct ___Object___ *obj=tagd->flagptr;
566       struct ___TagDescriptor___ *copy=((struct ___TagDescriptor___**)tagd)[1];
567       if (obj==NULL) {
568         /* Zero object case */
569       } else if (obj->type==-1) {
570         /* Single object case */
571         copy->flagptr=((struct ___Object___**)obj)[1];
572       } else if (obj->type==OBJECTARRAYTYPE) {
573         /* Array case */
574         struct ArrayObject *ao=(struct ArrayObject *) obj;
575         int livecount=0;
576         int j;
577         int k=0;
578         struct ArrayObject *aonew;
579
580         /* Count live objects */
581         for(j=0; j<ao->___cachedCode___; j++) {
582           struct ___Object___ * tobj=ARRAYGET(ao, struct ___Object___ *, j);
583           if (tobj->type==-1)
584             livecount++;
585         }
586
587         livecount=((livecount-1)/OBJECTARRAYINTERVAL+1)*OBJECTARRAYINTERVAL;
588         aonew=(struct ArrayObject *) tomalloc(sizeof(struct ArrayObject)+sizeof(struct ___Object___*)*livecount);
589         memcpy(aonew, ao, sizeof(struct ArrayObject));
590         aonew->type=OBJECTARRAYTYPE;
591         aonew->___length___=livecount;
592         copy->flagptr=aonew;
593         for(j=0; j<ao->___cachedCode___; j++) {
594           struct ___Object___ * tobj=ARRAYGET(ao, struct ___Object___ *, j);
595           if (tobj->type==-1) {
596             struct ___Object___ * tobjcpy=((struct ___Object___**)tobj)[1];
597             ARRAYSET(aonew, struct ___Object___*, k++,tobjcpy);
598           }
599         }
600         aonew->___cachedCode___=k;
601         for(; k<livecount; k++) {
602           ARRAYSET(aonew, struct ___Object___*, k, NULL);
603         }
604       } else {
605         /* No object live anymore */
606         copy->flagptr=NULL;
607       }
608     }
609     free(taghead);
610     taghead=tmp;
611     tagindex=NUMPTRS;
612   }
613 }
614 #endif
615
616 void * tomalloc(int size) {
617   void * ptr=to_heapptr;
618   if ((size&7)!=0)
619     size+=(8-(size%8));
620   to_heapptr+=size;
621   return ptr;
622 }
623
624 #if defined(THREADS)||defined(DSTM)||defined(STM)
625 void checkcollect(void * ptr) {
626   stopforgc((struct garbagelist *)ptr);
627   restartaftergc();
628 }
629
630 #ifdef DSTM
631 void checkcollect2(void * ptr) {
632   int ptrarray[]={1, (int)ptr, (int) revertlist};
633   stopforgc((struct garbagelist *)ptrarray);
634   restartaftergc();
635   revertlist=(struct ___Object___*)ptrarray[2];
636 }
637 #endif
638
639 void stopforgc(struct garbagelist * ptr) {
640 #ifdef DELAYCOMP
641   //just append us to the list
642   ptrstack.prev=ptr;
643   ptr=(struct garbagelist *) &ptrstack;
644 #endif
645 #ifndef MAC
646   litem.stackptr=ptr;
647 #ifdef THREADS
648   litem.locklist=pthread_getspecific(threadlocks);
649 #endif
650 #ifdef STM
651   litem.tc_size=c_size;
652   litem.tc_table=&c_table;
653   litem.tc_list=&c_list;
654   litem.tc_structs=&c_structs;
655   litem.objlist=newobjs;
656 #ifdef STMSTATS
657   litem.lockedlist=lockedobjs;
658 #endif
659   litem.base=&memorybase;
660 #endif
661 #else
662   //handle MAC
663   struct listitem *litem=pthread_getspecific(litemkey);
664   litem->stackptr=ptr;
665 #ifdef THREADS
666   litem->locklist=pthread_getspecific(threadlocks);
667 #endif
668 #endif
669   pthread_mutex_lock(&gclistlock);
670   listcount++;
671   if ((listcount+1)==threadcount) {
672     //only do wakeup if we are ready to GC
673     pthread_cond_signal(&gccond);
674   }
675   pthread_mutex_unlock(&gclistlock);
676 }
677
678 void restartaftergc() {
679   if (needtocollect) {
680     pthread_mutex_lock(&gclock); // Wait for GC
681     pthread_mutex_unlock(&gclock);
682   }
683   pthread_mutex_lock(&gclistlock);
684   listcount--;
685   pthread_mutex_unlock(&gclistlock);
686 }
687 #endif
688
689 #if defined(STM)||defined(THREADS)
690 #define MEMORYBLOCK 65536
691 void * helper(struct garbagelist *, int);
692 void * mygcmalloc(struct garbagelist * stackptr, int size) {
693   if ((size&7)!=0)
694     size=(size&~7)+8;
695   if (memorybase==NULL||size>(memorytop-memorybase)) {
696     int toallocate=(size>MEMORYBLOCK)?size:MEMORYBLOCK;
697     memorybase=helper(stackptr, toallocate);
698     memorytop=memorybase+toallocate;
699   }
700   char *retvalue=memorybase;
701   memorybase+=size;
702   return retvalue;
703 }
704
705 void * helper(struct garbagelist * stackptr, int size) {
706 #else
707 void * mygcmalloc(struct garbagelist * stackptr, int size) {
708 #endif
709   void *ptr;
710 #if defined(THREADS)||defined(DSTM)||defined(STM)
711   while (pthread_mutex_trylock(&gclock)!=0) {
712     stopforgc(stackptr);
713     restartaftergc();
714   }
715 #endif
716   ptr=curr_heapptr;
717   if ((size&7)!=0)
718     size=(size&~7)+8;
719   curr_heapptr+=size;
720   if (curr_heapptr>curr_heapgcpoint||curr_heapptr<curr_heapbase) {
721     if (curr_heapbase==0) {
722       /* Need to allocate base heap */
723       curr_heapbase=malloc(INITIALHEAPSIZE);
724       if (curr_heapbase==NULL) {
725         printf("malloc failed.  Garbage collector couldn't get enough memory.  Try changing heap size.\n");
726         exit(-1);
727       }
728       bzero(curr_heapbase, INITIALHEAPSIZE);
729       curr_heaptop=curr_heapbase+INITIALHEAPSIZE;
730       curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(INITIALHEAPSIZE);
731       curr_heapptr=curr_heapbase+size;
732
733       to_heapbase=malloc(INITIALHEAPSIZE);
734       if (to_heapbase==NULL) {
735         printf("malloc failed.  Garbage collector couldn't get enough memory.  Try changing heap size.\n");
736         exit(-1);
737       }
738       to_heaptop=to_heapbase+INITIALHEAPSIZE;
739       to_heapptr=to_heapbase;
740       ptr=curr_heapbase;
741 #if defined(THREADS)||defined(DSTM)||defined(STM)
742       pthread_mutex_unlock(&gclock);
743 #endif
744       return ptr;
745     }
746
747     /* Grow the to heap if necessary */
748     {
749       INTPTR curr_heapsize=curr_heaptop-curr_heapbase;
750       INTPTR to_heapsize=to_heaptop-to_heapbase;
751       INTPTR last_heapsize=0;
752       if (lastgcsize>0) {
753         last_heapsize=HEAPSIZE(lastgcsize, size);
754         if ((last_heapsize&7)!=0)
755           last_heapsize+=(8-(last_heapsize%8));
756       }
757       if (curr_heapsize>last_heapsize)
758         last_heapsize=curr_heapsize;
759       if (last_heapsize>to_heapsize) {
760         free(to_heapbase);
761         to_heapbase=malloc(last_heapsize);
762         if (to_heapbase==NULL) {
763           printf("Error Allocating enough memory\n");
764           exit(-1);
765         }
766         to_heaptop=to_heapbase+last_heapsize;
767         to_heapptr=to_heapbase;
768       }
769     }
770
771     /* Do our collection */
772     collect(stackptr);
773
774     /* Update stat on previous gc size */
775     lastgcsize=(to_heapptr-to_heapbase)+size;
776
777 #ifdef GARBAGESTATS
778     printf("Garbage collected: Old bytes: %u\n", curr_heapptr-curr_heapbase);
779     printf("New space: %u\n", to_heapptr-to_heapbase);
780     printf("Total space: %u\n", to_heaptop-to_heapbase);
781     {
782       int i;
783       for(i=0;i<MAXSTATS;i++) {
784         if (garbagearray[i]!=0)
785           printf("Type=%d Size=%u\n", i, garbagearray[i]);
786       }
787     }
788 #endif
789     /* Flip to/curr heaps */
790     {
791       void * tmp=to_heapbase;
792       to_heapbase=curr_heapbase;
793       curr_heapbase=tmp;
794
795       tmp=to_heaptop;
796       to_heaptop=curr_heaptop;
797       curr_heaptop=tmp;
798
799       tmp=to_heapptr;
800       curr_heapptr=to_heapptr+size;
801       curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(curr_heaptop-curr_heapbase);
802       to_heapptr=to_heapbase;
803
804       /* Not enough room :(, redo gc */
805       if (curr_heapptr>curr_heapgcpoint) {
806 #if defined(THREADS)||defined(DSTM)||defined(STM)
807         pthread_mutex_unlock(&gclock);
808 #endif
809         return mygcmalloc(stackptr, size);
810       }
811
812       bzero(tmp, curr_heaptop-tmp);
813 #if defined(THREADS)||defined(DSTM)||defined(STM)
814       pthread_mutex_unlock(&gclock);
815 #endif
816       return tmp;
817     }
818   } else {
819 #if defined(THREADS)||defined(DSTM)||defined(STM)
820     pthread_mutex_unlock(&gclock);
821 #endif
822     return ptr;
823   }
824 }
825
826
827 int gc_createcopy(void * orig, void ** copy_ptr) {
828   if (orig==0) {
829     *copy_ptr=NULL;
830     return 0;
831   } else {
832     int type=((int *)orig)[0];
833     if (type==-1) {
834       *copy_ptr=((void **)orig)[1];
835       return 0;
836     }
837     if (type<NUMCLASSES) {
838       /* We have a normal object */
839 #ifdef STM
840       int size=classsize[type]+sizeof(objheader_t);
841       void *newobj=tomalloc(size);
842       memcpy(newobj,((char *) orig)-sizeof(objheader_t), size);
843       newobj=((char *)newobj)+sizeof(objheader_t);
844 #else
845       int size=classsize[type];
846       void *newobj=tomalloc(size);
847       memcpy(newobj, orig, size);
848 #endif
849 #ifdef GARBAGESTATS
850       garbagearray[type]+=size;
851 #endif
852       ((int *)orig)[0]=-1;
853       ((void **)orig)[1]=newobj;
854       *copy_ptr=newobj;
855       return 1;
856     } else {
857       /* We have an array */
858       struct ArrayObject *ao=(struct ArrayObject *)orig;
859       int elementsize=classsize[type];
860       int length=ao->___length___;
861 #ifdef STM
862       int size=sizeof(struct ArrayObject)+length*elementsize+sizeof(objheader_t);
863       void *newobj=tomalloc(size);
864       memcpy(newobj, ((char*)orig)-sizeof(objheader_t), size);
865       newobj=((char *)newobj)+sizeof(objheader_t);
866 #else
867       int size=sizeof(struct ArrayObject)+length*elementsize;
868       void *newobj=tomalloc(size);
869       memcpy(newobj, orig, size);
870 #endif
871 #ifdef GARBAGESTATS
872       garbagearray[type]+=size;
873 #endif
874       ((int *)orig)[0]=-1;
875       ((void **)orig)[1]=newobj;
876       *copy_ptr=newobj;
877       return 1;
878     }
879   }
880 }