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