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