fix compile
[IRC.git] / Robust / src / Runtime / garbage.c
1 #include "garbage.h"
2 #include "runtime.h"
3 #include "structdefs.h"
4 #include "Queue.h"
5 #include "SimpleHash.h"
6 #include "chash.h"
7 #include "GenericHashtable.h"
8 #include <string.h>
9 #if defined(THREADS) || defined(DSTM) || defined(STM)
10 #include "thread.h"
11 #endif
12
13 #ifdef DMALLOC
14 #include "dmalloc.h"
15 #endif
16 #ifdef DSTM
17 #include "dstm.h"
18 #endif
19 #ifdef STM
20 #include "tm.h"
21 #endif
22
23 #define NUMPTRS 100
24
25 #define INITIALHEAPSIZE 32*1024*1024
26 #define GCPOINT(x) ((int)((x)*0.9))
27 /* This define takes in how full the heap is initially and returns a new heap size to use */
28 #define HEAPSIZE(x,y) (((int)((x)/0.6))+y)
29
30 #ifdef TASK
31 extern struct genhashtable * activetasks;
32 #ifndef MULTICORE
33 extern struct parameterwrapper * objectqueues[NUMCLASSES];
34 #endif
35 extern struct genhashtable * failedtasks;
36 extern struct taskparamdescriptor *currtpd;
37 extern struct ctable *forward;
38 extern struct ctable *reverse;
39 extern struct RuntimeHash *fdtoobject;
40 #endif
41
42 #if defined(THREADS) || defined(DSTM) || defined(STM)
43 int needtocollect=0;
44 struct listitem * list=NULL;
45 int listcount=0;
46 #endif
47
48 //Need to check if pointers are transaction pointers
49 //this also catches the special flag value of 1 for local copies
50 #ifdef DSTM
51 #define ENQUEUE(orig, dst) \
52   if ((!(((unsigned int)orig)&0x1))) { \
53     if (orig>=curr_heapbase&&orig<curr_heaptop) { \
54       void *copy; \
55       if (gc_createcopy(orig,&copy)) \
56         enqueue(orig);\
57       dst=copy; \
58     } \
59   }
60 #elif STM
61 #define ENQUEUE(orig, dst) \
62   if ((!(((unsigned int)orig)&0x1))) { \
63     if (orig>=curr_heapbase&&orig<curr_heaptop) { \
64       void *copy; \
65       if (gc_createcopy(orig,&copy)) \
66         enqueue(orig);\
67       dst=copy; \
68     } \
69   }
70 #elif defined(FASTCHECK)
71 #define ENQUEUE(orig, dst) \
72   if (((unsigned int)orig)!=1) { \
73     void *copy; \
74     if (gc_createcopy(orig,&copy)) \
75       enqueue(orig);\
76     dst=copy; }
77 #else
78 #define ENQUEUE(orig, dst) \
79   void *copy; \
80   if (gc_createcopy(orig,&copy)) \
81     enqueue(orig);\
82   dst=copy
83 #endif
84
85 struct pointerblock {
86   void * ptrs[NUMPTRS];
87   struct pointerblock *next;
88 };
89
90 void * curr_heapbase=0;
91 void * curr_heapptr=0;
92 void * curr_heapgcpoint=0;
93 void * curr_heaptop=0;
94
95 void * to_heapbase=0;
96 void * to_heapptr=0;
97 void * to_heaptop=0;
98 long lastgcsize=0;
99
100 struct pointerblock *head=NULL;
101 int headindex=0;
102 struct pointerblock *tail=NULL;
103 int tailindex=0;
104 struct pointerblock *spare=NULL;
105
106 void enqueue(void *ptr) {
107   if (headindex==NUMPTRS) {
108     struct pointerblock * tmp;
109     if (spare!=NULL) {
110       tmp=spare;
111       spare=NULL;
112     } else
113       tmp=malloc(sizeof(struct pointerblock));
114     head->next=tmp;
115     head=tmp;
116     headindex=0;
117   }
118   head->ptrs[headindex++]=ptr;
119 }
120
121 void * dequeue() {
122   if (tailindex==NUMPTRS) {
123     struct pointerblock *tmp=tail;
124     tail=tail->next;
125     tailindex=0;
126     if (spare!=NULL)
127       free(tmp);
128     else
129       spare=tmp;
130   }
131   return tail->ptrs[tailindex++];
132 }
133
134 int moreItems() {
135   if ((head==tail)&&(tailindex==headindex))
136     return 0;
137   return 1;
138 }
139
140 #ifdef TASK
141 struct pointerblock *taghead=NULL;
142 int tagindex=0;
143
144 void enqueuetag(struct ___TagDescriptor___ *ptr) {
145   if (tagindex==NUMPTRS) {
146     struct pointerblock * tmp=malloc(sizeof(struct pointerblock));
147     tmp->next=taghead;
148     taghead=tmp;
149     tagindex=0;
150   }
151   taghead->ptrs[tagindex++]=ptr;
152 }
153 #endif
154
155
156 void collect(struct garbagelist * stackptr) {
157 #if defined(THREADS)||defined(DSTM)||defined(STM)
158   needtocollect=1;
159   pthread_mutex_lock(&gclistlock);
160   while(1) {
161     if ((listcount+1)==threadcount) {
162       break; /* Have all other threads stopped */
163     }
164     pthread_cond_wait(&gccond, &gclistlock);
165   }
166 #endif
167
168   if (head==NULL) {
169     headindex=0;
170     tailindex=0;
171     head=tail=malloc(sizeof(struct pointerblock));
172   }
173
174 #ifdef TASK
175   if (taghead==NULL) {
176     tagindex=0;
177     taghead=malloc(sizeof(struct pointerblock));
178     taghead->next=NULL;
179   }
180 #endif
181
182   /* Check current stack */
183 #if defined(THREADS)||defined(DSTM)||defined(STM)
184   {
185     struct listitem *listptr=list;
186     while(1) {
187 #endif
188
189   while(stackptr!=NULL) {
190     int i;
191     for(i=0; i<stackptr->size; i++) {
192       void * orig=stackptr->array[i];
193       ENQUEUE(orig, stackptr->array[i]);
194     }
195     stackptr=stackptr->next;
196   }
197 #if defined(THREADS)||defined(DSTM)||defined(STM)
198   /* Go to next thread */
199   if (listptr!=NULL) {
200 #ifdef THREADS
201     void * orig=listptr->locklist;
202     ENQUEUE(orig, listptr->locklist);
203 #endif
204     stackptr=listptr->stackptr;
205     listptr=listptr->next;
206   } else
207     break;
208 }
209 }
210 #endif
211
212 #ifdef FASTCHECK
213   ENQUEUE(___fcrevert___, ___fcrevert___);
214 #endif
215
216 #ifdef TASK
217   {
218     /* Update objectsets */
219     int i;
220     for(i=0; i<NUMCLASSES; i++) {
221 #if !defined(MULTICORE)
222       struct parameterwrapper * p=objectqueues[i];
223       while(p!=NULL) {
224         struct ObjectHash * set=p->objectset;
225         struct ObjectNode * ptr=set->listhead;
226         while(ptr!=NULL) {
227           void *orig=(void *)ptr->key;
228           ENQUEUE(orig, *((void **)(&ptr->key)));
229           ptr=ptr->lnext;
230         }
231         ObjectHashrehash(set); /* Rehash the table */
232         p=p->next;
233       }
234 #endif
235     }
236   }
237
238 #ifndef FASTCHECK
239   if (forward!=NULL) {
240     struct cnode * ptr=forward->listhead;
241     while(ptr!=NULL) {
242       void * orig=(void *)ptr->key;
243       ENQUEUE(orig, *((void **)(&ptr->key)));
244       ptr=ptr->lnext;
245     }
246     crehash(forward); /* Rehash the table */
247   }
248
249   if (reverse!=NULL) {
250     struct cnode * ptr=reverse->listhead;
251     while(ptr!=NULL) {
252       void *orig=(void *)ptr->val;
253       ENQUEUE(orig, *((void**)(&ptr->val)));
254       ptr=ptr->lnext;
255     }
256   }
257 #endif
258
259   {
260     struct RuntimeNode * ptr=fdtoobject->listhead;
261     while(ptr!=NULL) {
262       void *orig=(void *)ptr->data;
263       ENQUEUE(orig, *((void**)(&ptr->data)));
264       ptr=ptr->lnext;
265     }
266   }
267
268   {
269     /* Update current task descriptor */
270     int i;
271     for(i=0; i<currtpd->numParameters; i++) {
272       void *orig=currtpd->parameterArray[i];
273       ENQUEUE(orig, currtpd->parameterArray[i]);
274     }
275
276   }
277
278   /* Update active tasks */
279   {
280     struct genpointerlist * ptr=activetasks->list;
281     while(ptr!=NULL) {
282       struct taskparamdescriptor *tpd=ptr->src;
283       int i;
284       for(i=0; i<tpd->numParameters; i++) {
285         void * orig=tpd->parameterArray[i];
286         ENQUEUE(orig, tpd->parameterArray[i]);
287       }
288       ptr=ptr->inext;
289     }
290     genrehash(activetasks);
291   }
292
293   /* Update failed tasks */
294   {
295     struct genpointerlist * ptr=failedtasks->list;
296     while(ptr!=NULL) {
297       struct taskparamdescriptor *tpd=ptr->src;
298       int i;
299       for(i=0; i<tpd->numParameters; i++) {
300         void * orig=tpd->parameterArray[i];
301         ENQUEUE(orig, tpd->parameterArray[i]);
302       }
303       ptr=ptr->inext;
304     }
305     genrehash(failedtasks);
306   }
307 #endif
308
309   while(moreItems()) {
310     void * ptr=dequeue();
311     void *cpy=((void **)ptr)[1];
312     int type=((int *)cpy)[0];
313     unsigned int * pointer;
314 #ifdef TASK
315     if(type==TAGTYPE) {
316       /* Enqueue Tag */
317       /* Nothing is inside */
318       enqueuetag(ptr);
319       continue;
320     }
321 #endif
322     pointer=pointerarray[type];
323     if (pointer==0) {
324       /* Array of primitives */
325       /* Do nothing */
326 #if defined(DSTM)||defined(FASTCHECK)
327       struct ArrayObject *ao=(struct ArrayObject *) ptr;
328       struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
329       ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
330       ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
331 #endif
332     } else if (((int)pointer)==1) {
333       /* Array of pointers */
334       struct ArrayObject *ao=(struct ArrayObject *) ptr;
335       struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
336 #if (defined(DSTM)||defined(FASTCHECK))
337       ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
338       ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
339 #endif
340       int length=ao->___length___;
341       int i;
342       for(i=0; i<length; i++) {
343         void *objptr=((void **)(((char *)&ao->___length___)+sizeof(int)))[i];
344         ENQUEUE(objptr, ((void **)(((char *)&ao_cpy->___length___)+sizeof(int)))[i]);
345       }
346     } else {
347       int size=pointer[0];
348       int i;
349       for(i=1; i<=size; i++) {
350         unsigned int offset=pointer[i];
351         void * objptr=*((void **)(((int)ptr)+offset));
352         ENQUEUE(objptr, *((void **)(((int)cpy)+offset)));
353       }
354     }
355   }
356 #ifdef TASK
357   fixtags();
358 #endif
359
360 #if defined(THREADS)||defined(DSTM)
361   needtocollect=0;
362   pthread_mutex_unlock(&gclistlock);
363 #endif
364 }
365
366 #ifdef TASK
367 /* Fix up the references from tags.  This can't be done earlier,
368    because we don't want tags to keep objects alive */
369 void fixtags() {
370   while(taghead!=NULL) {
371     int i;
372     struct pointerblock *tmp=taghead->next;
373     for(i=0; i<tagindex; i++) {
374       struct ___TagDescriptor___ *tagd=taghead->ptrs[i];
375       struct ___Object___ *obj=tagd->flagptr;
376       struct ___TagDescriptor___ *copy=((struct ___TagDescriptor___**)tagd)[1];
377       if (obj==NULL) {
378         /* Zero object case */
379       } else if (obj->type==-1) {
380         /* Single object case */
381         copy->flagptr=((struct ___Object___**)obj)[1];
382       } else if (obj->type==OBJECTARRAYTYPE) {
383         /* Array case */
384         struct ArrayObject *ao=(struct ArrayObject *) obj;
385         int livecount=0;
386         int j;
387         int k=0;
388         struct ArrayObject *aonew;
389
390         /* Count live objects */
391         for(j=0; j<ao->___cachedCode___; j++) {
392           struct ___Object___ * tobj=ARRAYGET(ao, struct ___Object___ *, j);
393           if (tobj->type==-1)
394             livecount++;
395         }
396
397         livecount=((livecount-1)/OBJECTARRAYINTERVAL+1)*OBJECTARRAYINTERVAL;
398         aonew=(struct ArrayObject *) tomalloc(sizeof(struct ArrayObject)+sizeof(struct ___Object___*)*livecount);
399         memcpy(aonew, ao, sizeof(struct ArrayObject));
400         aonew->type=OBJECTARRAYTYPE;
401         aonew->___length___=livecount;
402         copy->flagptr=aonew;
403         for(j=0; j<ao->___cachedCode___; j++) {
404           struct ___Object___ * tobj=ARRAYGET(ao, struct ___Object___ *, j);
405           if (tobj->type==-1) {
406             struct ___Object___ * tobjcpy=((struct ___Object___**)tobj)[1];
407             ARRAYSET(aonew, struct ___Object___*, k++,tobjcpy);
408           }
409         }
410         aonew->___cachedCode___=k;
411         for(; k<livecount; k++) {
412           ARRAYSET(aonew, struct ___Object___*, k, NULL);
413         }
414       } else {
415         /* No object live anymore */
416         copy->flagptr=NULL;
417       }
418     }
419     free(taghead);
420     taghead=tmp;
421     tagindex=NUMPTRS;
422   }
423 }
424 #endif
425
426 void * tomalloc(int size) {
427   void * ptr=to_heapptr;
428   if ((size&7)!=0)
429     size+=(8-(size%8));
430   to_heapptr+=size;
431   return ptr;
432 }
433
434 #if defined(THREADS)||defined(DSTM)||defined(STM)
435 void checkcollect(void * ptr) {
436   struct listitem * tmp=stopforgc((struct garbagelist *)ptr);
437   pthread_mutex_lock(&gclock); // Wait for GC
438   restartaftergc(tmp);
439   pthread_mutex_unlock(&gclock);
440 }
441
442 #ifdef DSTM
443 void checkcollect2(void * ptr) {
444   int ptrarray[]={1, (int)ptr, (int) revertlist};
445   struct listitem * tmp=stopforgc((struct garbagelist *)ptrarray);
446   pthread_mutex_lock(&gclock); // Wait for GC
447   restartaftergc(tmp);
448   pthread_mutex_unlock(&gclock);
449   revertlist=(struct ___Object___*)ptrarray[2];
450 }
451 #endif
452
453
454 struct listitem * stopforgc(struct garbagelist * ptr) {
455   struct listitem * litem=malloc(sizeof(struct listitem));
456   litem->stackptr=ptr;
457 #ifdef THREADS
458   litem->locklist=pthread_getspecific(threadlocks);
459 #endif
460 #ifdef STM
461   litem->tc_size=c_size;
462   litem->tc_mask=c_mask;
463   litem->tc_table=&c_table;
464 #endif
465   litem->prev=NULL;
466   pthread_mutex_lock(&gclistlock);
467   litem->next=list;
468   if(list!=NULL)
469     list->prev=litem;
470   list=litem;
471   listcount++;
472   pthread_cond_signal(&gccond);
473   pthread_mutex_unlock(&gclistlock);
474   return litem;
475 }
476
477 void restartaftergc(struct listitem * litem) {
478   pthread_mutex_lock(&gclistlock);
479 #ifdef THREADS
480   pthread_setspecific(threadlocks, litem->locklist);
481 #endif
482   if (litem->prev==NULL) {
483     list=litem->next;
484   } else {
485     litem->prev->next=litem->next;
486   }
487   if (litem->next!=NULL) {
488     litem->next->prev=litem->prev;
489   }
490   listcount--;
491   pthread_mutex_unlock(&gclistlock);
492   free(litem);
493 }
494 #endif
495
496 void * mygcmalloc(struct garbagelist * stackptr, int size) {
497   void *ptr;
498 #if defined(THREADS)||defined(DSTM)||defined(STM)
499   if (pthread_mutex_trylock(&gclock)!=0) {
500     struct listitem *tmp=stopforgc(stackptr);
501     pthread_mutex_lock(&gclock);
502     restartaftergc(tmp);
503   }
504 #endif
505   ptr=curr_heapptr;
506   if ((size&7)!=0)
507     size+=(8-(size%8));
508   curr_heapptr+=size;
509   if (curr_heapptr>curr_heapgcpoint) {
510     if (curr_heapbase==0) {
511       /* Need to allocate base heap */
512       curr_heapbase=malloc(INITIALHEAPSIZE);
513       bzero(curr_heapbase, INITIALHEAPSIZE);
514       curr_heaptop=curr_heapbase+INITIALHEAPSIZE;
515       curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(INITIALHEAPSIZE);
516       curr_heapptr=curr_heapbase+size;
517
518       to_heapbase=malloc(INITIALHEAPSIZE);
519       to_heaptop=to_heapbase+INITIALHEAPSIZE;
520       to_heapptr=to_heapbase;
521       ptr=curr_heapbase;
522 #if defined(THREADS)||defined(DSTM)||defined(STM)
523       pthread_mutex_unlock(&gclock);
524 #endif
525       return ptr;
526     }
527
528     /* Grow the to heap if necessary */
529     {
530       int curr_heapsize=curr_heaptop-curr_heapbase;
531       int to_heapsize=to_heaptop-to_heapbase;
532       int last_heapsize=0;
533       if (lastgcsize>0) {
534         last_heapsize=HEAPSIZE(lastgcsize, size);
535         if ((last_heapsize&7)!=0)
536           last_heapsize+=(8-(last_heapsize%8));
537       }
538       if (curr_heapsize>last_heapsize)
539         last_heapsize=curr_heapsize;
540       if (last_heapsize>to_heapsize) {
541         free(to_heapbase);
542         to_heapbase=malloc(last_heapsize);
543         if (to_heapbase==NULL) {
544           printf("Error Allocating enough memory\n");
545           exit(-1);
546         }
547         to_heaptop=to_heapbase+last_heapsize;
548         to_heapptr=to_heapbase;
549       }
550     }
551
552     /* Do our collection */
553     collect(stackptr);
554
555     /* Update stat on previous gc size */
556     lastgcsize=(to_heapptr-to_heapbase)+size;
557
558     /* Flip to/curr heaps */
559     {
560       void * tmp=to_heapbase;
561       to_heapbase=curr_heapbase;
562       curr_heapbase=tmp;
563
564       tmp=to_heaptop;
565       to_heaptop=curr_heaptop;
566       curr_heaptop=tmp;
567
568       tmp=to_heapptr;
569       curr_heapptr=to_heapptr+size;
570       curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(curr_heaptop-curr_heapbase);
571       to_heapptr=to_heapbase;
572
573       /* Not enough room :(, redo gc */
574       if (curr_heapptr>curr_heapgcpoint) {
575 #if defined(THREADS)||defined(DSTM)||defined(STM)
576         pthread_mutex_unlock(&gclock);
577 #endif
578         return mygcmalloc(stackptr, size);
579       }
580
581       bzero(tmp, curr_heaptop-tmp);
582 #if defined(THREADS)||defined(DSTM)||defined(STM)
583       pthread_mutex_unlock(&gclock);
584 #endif
585       return tmp;
586     }
587   } else {
588 #if defined(THREADS)||defined(DSTM)||defined(STM)
589     pthread_mutex_unlock(&gclock);
590 #endif
591     return ptr;
592   }
593 }
594
595
596 int gc_createcopy(void * orig, void ** copy_ptr) {
597   if (orig==0) {
598     *copy_ptr=NULL;
599     return 0;
600   } else {
601     int type=((int *)orig)[0];
602     if (type==-1) {
603       *copy_ptr=((void **)orig)[1];
604       return 0;
605     }
606     if (type<NUMCLASSES) {
607       /* We have a normal object */
608       int size=classsize[type];
609       void *newobj=tomalloc(size);
610       memcpy(newobj, orig, size);
611       ((int *)orig)[0]=-1;
612       ((void **)orig)[1]=newobj;
613       *copy_ptr=newobj;
614       return 1;
615     } else {
616       /* We have an array */
617       struct ArrayObject *ao=(struct ArrayObject *)orig;
618       int elementsize=classsize[type];
619       int length=ao->___length___;
620       int size=sizeof(struct ArrayObject)+length*elementsize;
621       void *newobj=tomalloc(size);
622       memcpy(newobj, orig, size);
623       ((int *)orig)[0]=-1;
624       ((void **)orig)[1]=newobj;
625       *copy_ptr=newobj;
626       return 1;
627     }
628   }
629 }