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