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