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