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