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