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 #ifdef MLP
13 #ifdef SQUEUE
14 #include "squeue.h"
15 #else
16 #include "deque.h"
17 #endif
18 #include "workschedule.h"
19 extern int    numWorkSchedWorkers;
20 extern deque* deques;
21 #endif
22
23 #ifdef DMALLOC
24 #include "dmalloc.h"
25 #endif
26 #ifdef DSTM
27 #ifdef RECOVERY
28 #include <DSTM/interface_recovery/dstm.h>
29 #else
30 #include <DSTM/interface/dstm.h>
31 #endif
32 #endif
33 #ifdef STM
34 #include "tm.h"
35 #endif
36 #ifdef DELAYCOMP
37 #include "delaycomp.h"
38 #endif
39
40
41 #define NUMPTRS 100
42
43 #ifndef INITIALHEAPSIZE_MB
44 #define INITIALHEAPSIZE_MB (256)
45 #endif
46
47 #define INITIALHEAPSIZE INITIALHEAPSIZE_MB*1024*1024L
48 #define GCPOINT(x) ((INTPTR)((x)*0.99))
49 /* This define takes in how full the heap is initially and returns a new heap size to use */
50 #define HEAPSIZE(x,y) ((INTPTR)(x+y))*2
51
52 #ifdef TASK
53 extern struct genhashtable * activetasks;
54 #ifndef MULTICORE
55 extern struct parameterwrapper * objectqueues[NUMCLASSES];
56 #endif
57 extern struct genhashtable * failedtasks;
58 extern struct taskparamdescriptor *currtpd;
59 extern struct ctable *forward;
60 extern struct ctable *reverse;
61 extern struct RuntimeHash *fdtoobject;
62 #endif
63
64 #ifdef GARBAGESTATS
65 #define MAXSTATS 500
66 long garbagearray[MAXSTATS];
67 #endif
68
69 #if defined(THREADS) || defined(DSTM) || defined(STM)||defined(MLP)
70 int needtocollect=0;
71 struct listitem * list=NULL;
72 int listcount=0;
73 #ifndef MAC
74 __thread struct listitem litem;
75 #endif
76 #endif
77
78 #ifdef MLP
79 __thread SESEcommon* seseCommon;
80 #endif
81
82 //Need to check if pointers are transaction pointers
83 //this also catches the special flag value of 1 for local copies
84 #ifdef DSTM
85 #define ENQUEUE(orig, dst) \
86   if ((!(((unsigned int)orig)&0x1))) { \
87     if (orig>=curr_heapbase&&orig<curr_heaptop) { \
88       void *copy; \
89       if (gc_createcopy(orig,&copy)) \
90         enqueue(copy);\
91       dst=copy; \
92     } \
93   }
94 #elif defined(STM)
95 #define ENQUEUE(orig, dst) \
96   if (orig>=curr_heapbase&&orig<curr_heaptop) { \
97     void *copy; \
98     if (gc_createcopy(orig,&copy)) \
99       enqueue(copy);\
100     dst=copy; \
101   }
102 #define SENQUEUE(orig, dst) \
103   { \
104     void *copy; \
105     if (gc_createcopy(orig,&copy)) \
106       enqueue(copy);\
107     dst=copy; \
108   }
109 #elif defined(FASTCHECK)
110 #define ENQUEUE(orig, dst) \
111   if (((unsigned int)orig)!=1) { \
112     void *copy; \
113     if (gc_createcopy(orig,&copy)) \
114       enqueue(copy);\
115     dst=copy; }
116 #else
117 #define ENQUEUE(orig, dst) \
118   if (orig>=curr_heapbase&&orig<curr_heaptop) { \
119      void *copy; \
120      if (gc_createcopy(orig,&copy)) \
121          enqueue(copy); \
122      dst=copy; \
123   }
124 #endif
125
126
127 struct pointerblock {
128   void * ptrs[NUMPTRS];
129   struct pointerblock *next;
130 };
131
132 void * curr_heapbase=0;
133 void * curr_heapptr=0;
134 void * curr_heapgcpoint=0;
135 void * curr_heaptop=0;
136
137 void * to_heapbase=0;
138 void * to_heapptr=0;
139 void * to_heaptop=0;
140 long lastgcsize=0;
141
142
143 struct pointerblock *head=NULL;
144 int headindex=0;
145 struct pointerblock *tail=NULL;
146 int tailindex=0;
147 struct pointerblock *spare=NULL;
148
149 void enqueue(void *ptr) {
150   if (headindex==NUMPTRS) {
151     struct pointerblock * tmp;
152     if (spare!=NULL) {
153       tmp=spare;
154       spare=NULL;
155     } else      tmp=malloc(sizeof(struct pointerblock));
156     head->next=tmp;
157     head=tmp;
158     headindex=0;
159   }
160   head->ptrs[headindex++]=ptr;
161 }
162
163 void * dequeue() {
164   if (tailindex==NUMPTRS) {
165     struct pointerblock *tmp=tail;
166     tail=tail->next;
167     tailindex=0;
168     if (spare!=NULL)
169       free(tmp);
170     else
171       spare=tmp;
172   }
173   return tail->ptrs[tailindex++];
174 }
175
176 #ifdef STM
177 void fixobjlist(struct objlist * ptr) {
178   while(ptr!=NULL) {
179     int i;
180     for(i=0;i<ptr->offset;i++) {
181       SENQUEUE(ptr->objs[i], ptr->objs[i]);
182     }
183     ptr=ptr->next;
184   }
185 }
186
187 void fixtable(chashlistnode_t ** tc_table, chashlistnode_t **tc_list, cliststruct_t **cstr, unsigned int tc_size) {
188   unsigned int mask=(tc_size<<4)-1;
189   chashlistnode_t *node=calloc(tc_size, sizeof(chashlistnode_t));
190   chashlistnode_t *ptr=*tc_table;
191   chashlistnode_t *curr;
192   unsigned int i;
193   unsigned int index;
194   int isfirst;
195   chashlistnode_t *newlist=NULL;
196   for(i=0;i<tc_size;i++) {
197     curr=&ptr[i];
198     isfirst=1;
199     do {                      //Inner loop to go through linked lists
200       void * key;
201       chashlistnode_t *tmp,*next;
202       
203       if ((key=(void *)curr->key) == 0) {             //Exit inner loop if there the first element is 0
204         break;                  //key = val =0 for element if not present within the hash table
205       }
206       SENQUEUE(key, key);
207       if (curr->val>=curr_heapbase&&curr->val<curr_heaptop) {
208         SENQUEUE(curr->val, curr->val);
209       } else {
210         //rewrite transaction cache entry
211         void *vptr=curr->val;
212         int type=((int *)vptr)[0];
213         unsigned INTPTR *pointer=pointerarray[type];
214         if (pointer==0) {
215           //array of primitives - do nothing
216           struct ArrayObject *ao=(struct ArrayObject *) vptr;
217           SENQUEUE((void *)ao->___objlocation___, *((void **)&ao->___objlocation___));
218         } else if (((INTPTR)pointer)==1) {
219           //array of pointers
220           struct ArrayObject *ao=(struct ArrayObject *) vptr;
221           int length=ao->___length___;
222           int i;
223           SENQUEUE((void *)ao->___objlocation___, *((void **)&ao->___objlocation___));
224 #ifdef STMARRAY
225           int lowindex=ao->lowindex;
226           int highindex=ao->highindex;
227           int j;
228           for(j=lowindex; j<=highindex; j++) {
229             unsigned int lockval;
230             GETLOCKVAL(lockval, ao, j);
231             if (lockval!=STMNONE) {
232               int lowi=(j<<INDEXSHIFT)/sizeof(void *);
233               int highi=lowi+(INDEXLENGTH/sizeof(void *));
234               for(i=lowi; i<highi;i++) {
235 #else
236               for(i=0; i<length; i++) {
237 #endif
238                 void *objptr=((void **)(((char *)&ao->___length___)+sizeof(int)))[i];
239                 SENQUEUE(objptr, ((void **)(((char *)&ao->___length___)+sizeof(int)))[i]);
240               }
241 #ifdef STMARRAY
242             }
243           }
244 #endif
245         } else {
246           INTPTR size=pointer[0];
247           int i;
248           for(i=1; i<=size; i++) {
249             unsigned int offset=pointer[i];
250             void * objptr=*((void **)(((char *)vptr)+offset));
251             SENQUEUE(objptr, *((void **)(((char *)vptr)+offset)));
252           }
253         }
254       }
255
256       next = curr->next;
257       index = (((unsigned INTPTR)key) & mask) >>4;
258
259       curr->key=key;
260       tmp=&node[index];
261       // Insert into the new table
262       if(tmp->key == 0) {
263         tmp->key = curr->key;
264         tmp->val = curr->val;
265         tmp->lnext=newlist;
266         newlist=tmp;
267       } else if (isfirst) {
268         chashlistnode_t *newnode;
269         if ((*cstr)->num<NUMCLIST) {
270           newnode=&(*cstr)->array[(*cstr)->num];
271           (*cstr)->num++;
272         } else {
273           //get new list
274           cliststruct_t *tcl=calloc(1,sizeof(cliststruct_t));
275           tcl->next=*cstr;
276           *cstr=tcl;
277           newnode=&tcl->array[0];
278           tcl->num=1;
279         }
280         newnode->key = curr->key;
281         newnode->val = curr->val;
282         newnode->next = tmp->next;
283         newnode->lnext=newlist;
284         newlist=newnode;
285         tmp->next=newnode;
286       } else {
287         curr->lnext=newlist;
288         newlist=curr;
289         curr->next=tmp->next;
290         tmp->next=curr;
291       }
292       isfirst = 0;
293       curr = next;
294     } while(curr!=NULL);
295   }
296   free(ptr);
297   (*tc_table)=node;
298   (*tc_list)=newlist;
299 }
300 #endif
301
302 int moreItems() {
303   if ((head==tail)&&(tailindex==headindex))
304     return 0;
305   return 1;
306 }
307
308 #ifdef TASK
309 struct pointerblock *taghead=NULL;
310 int tagindex=0;
311
312 void enqueuetag(struct ___TagDescriptor___ *ptr) {
313   if (tagindex==NUMPTRS) {
314     struct pointerblock * tmp=malloc(sizeof(struct pointerblock));
315     tmp->next=taghead;
316     taghead=tmp;
317     tagindex=0;
318   }
319   taghead->ptrs[tagindex++]=ptr;
320 }
321 #endif
322
323 #if defined(STM)||defined(THREADS)||defined(MLP)
324 __thread char * memorybase=NULL;
325 __thread char * memorytop=NULL;
326 #endif
327
328
329 void collect(struct garbagelist * stackptr) {
330 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
331   needtocollect=1;
332   pthread_mutex_lock(&gclistlock);
333   while(1) {
334     if ((listcount+1)==threadcount) {
335       break; /* Have all other threads stopped */
336     }
337     pthread_cond_wait(&gccond, &gclistlock);
338   }
339 #endif
340 #ifdef DELAYCOMP
341   ptrstack.prev=stackptr;
342   stackptr=(struct garbagelist *) &ptrstack;
343 #if defined(STMARRAY)&&!defined(DUALVIEW)
344   arraystack.prev=stackptr;
345   stackptr=(struct garbagelist *) &arraystack;
346 #endif
347 #endif
348
349 #ifdef GARBAGESTATS
350   {
351     int i;
352     for(i=0;i<MAXSTATS;i++)
353       garbagearray[i]=0;
354   }
355 #endif
356
357   if (head==NULL) {
358     headindex=0;
359     tailindex=0;
360     head=tail=malloc(sizeof(struct pointerblock));
361   }
362
363 #ifdef TASK
364   if (taghead==NULL) {
365     tagindex=0;
366     taghead=malloc(sizeof(struct pointerblock));
367     taghead->next=NULL;
368   }
369 #endif
370
371 #ifdef STM
372   if (c_table!=NULL) {
373     fixtable(&c_table, &c_list, &c_structs, c_size);
374     fixobjlist(newobjs);
375 #ifdef STMSTATS
376     fixobjlist(lockedobjs);
377 #endif
378   }
379 #endif
380 #if defined(STM)||defined(THREADS)||defined(MLP)
381   memorybase=NULL;
382 #endif
383  
384   /* Check current stack */
385 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
386   {
387     struct listitem *listptr=list;
388     while(1) {
389 #endif
390       
391   while(stackptr!=NULL) {
392     int i;
393     for(i=0; i<stackptr->size; i++) {
394       void * orig=stackptr->array[i];
395       ENQUEUE(orig, stackptr->array[i]);
396     }
397     stackptr=stackptr->next;
398   }
399 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
400   /* Go to next thread */
401 #ifndef MAC
402   //skip over us
403   if (listptr==&litem) {
404 #ifdef MLP
405     // update forward list & memory queue for the current SESE
406     updateForwardList(((SESEcommon*)listptr->seseCommon)->forwardList,FALSE);
407     updateMemoryQueue((SESEcommon*)(listptr->seseCommon));
408 #endif
409     listptr=listptr->next;
410   }
411 #else
412  {
413   struct listitem *litem=pthread_getspecific(litemkey);
414   if (listptr==litem) {
415     listptr=listptr->next;
416   }
417  }
418 #endif
419  
420   if (listptr!=NULL) {
421 #ifdef THREADS
422     void * orig=listptr->locklist;
423     ENQUEUE(orig, listptr->locklist);
424 #endif
425 #ifdef STM
426     if ((*listptr->tc_table)!=NULL) {
427       fixtable(listptr->tc_table, listptr->tc_list, listptr->tc_structs, listptr->tc_size);
428       fixobjlist(listptr->objlist);
429 #ifdef STMSTATS
430       fixobjlist(listptr->lockedlist);
431 #endif
432     }
433 #endif
434 #if defined(STM)||defined(THREADS)||defined(MLP)
435     *(listptr->base)=NULL;
436 #endif
437 #ifdef MLP
438     // update forward list & memory queue for all running SESEs.
439     updateForwardList(((SESEcommon*)listptr->seseCommon)->forwardList,FALSE);
440     updateMemoryQueue((SESEcommon*)(listptr->seseCommon));
441 #endif
442     stackptr=listptr->stackptr;
443     listptr=listptr->next;
444   } else
445     break;
446 }
447 }
448 #endif
449
450 #ifdef FASTCHECK
451   ENQUEUE(___fcrevert___, ___fcrevert___);
452 #endif
453
454 #ifdef TASK
455   {
456     /* Update objectsets */
457     int i;
458     for(i=0; i<NUMCLASSES; i++) {
459 #if !defined(MULTICORE)
460       struct parameterwrapper * p=objectqueues[i];
461       while(p!=NULL) {
462         struct ObjectHash * set=p->objectset;
463         struct ObjectNode * ptr=set->listhead;
464         while(ptr!=NULL) {
465           void *orig=(void *)ptr->key;
466           ENQUEUE(orig, *((void **)(&ptr->key)));
467           ptr=ptr->lnext;
468         }
469         ObjectHashrehash(set); /* Rehash the table */
470         p=p->next;
471       }
472 #endif
473     }
474   }
475
476 #ifndef FASTCHECK
477   if (forward!=NULL) {
478     struct cnode * ptr=forward->listhead;
479     while(ptr!=NULL) {
480       void * orig=(void *)ptr->key;
481       ENQUEUE(orig, *((void **)(&ptr->key)));
482       ptr=ptr->lnext;
483     }
484     crehash(forward); /* Rehash the table */
485   }
486
487   if (reverse!=NULL) {
488     struct cnode * ptr=reverse->listhead;
489     while(ptr!=NULL) {
490       void *orig=(void *)ptr->val;
491       ENQUEUE(orig, *((void**)(&ptr->val)));
492       ptr=ptr->lnext;
493     }
494   }
495 #endif
496
497   {
498     struct RuntimeNode * ptr=fdtoobject->listhead;
499     while(ptr!=NULL) {
500       void *orig=(void *)ptr->data;
501       ENQUEUE(orig, *((void**)(&ptr->data)));
502       ptr=ptr->lnext;
503     }
504   }
505
506   {
507     /* Update current task descriptor */
508     int i;
509     for(i=0; i<currtpd->numParameters; i++) {
510       void *orig=currtpd->parameterArray[i];
511       ENQUEUE(orig, currtpd->parameterArray[i]);
512     }
513
514   }
515
516   /* Update active tasks */
517   {
518     struct genpointerlist * ptr=activetasks->list;
519     while(ptr!=NULL) {
520       struct taskparamdescriptor *tpd=ptr->src;
521       int i;
522       for(i=0; i<tpd->numParameters; i++) {
523         void * orig=tpd->parameterArray[i];
524         ENQUEUE(orig, tpd->parameterArray[i]);
525       }
526       ptr=ptr->inext;
527     }
528     genrehash(activetasks);
529   }
530
531   /* Update failed tasks */
532   {
533     struct genpointerlist * ptr=failedtasks->list;
534     while(ptr!=NULL) {
535       struct taskparamdescriptor *tpd=ptr->src;
536       int i;
537       for(i=0; i<tpd->numParameters; i++) {
538         void * orig=tpd->parameterArray[i];
539         ENQUEUE(orig, tpd->parameterArray[i]);
540       }
541       ptr=ptr->inext;
542     }
543     genrehash(failedtasks);
544   }
545 #endif
546
547 #ifdef MLP
548 #ifdef SQUEUE
549   {
550     int        i;
551     deque*     dq;
552     dequeItem *di;
553     int        j;
554
555     // goes over ready-to-run SESEs
556     for( i = 0; i < numWorkSchedWorkers; ++i ) {
557       dq = &(deques[i]);
558
559       di=dq->head;
560
561       do {
562         // check all the relevant indices of this
563         // node in the deque, noting if we are in
564         // the top/bottom node which can be partially
565         // full
566
567           // WHAT? 
568           //SESEcommon* common = (SESEcommon*) n->itsDataArr[j];
569           //if(common==seseCommon){
570           // skip the current running SESE
571           //  continue;
572           //}
573
574         SESEcommon* seseRec = (SESEcommon*) di->work;
575           struct garbagelist* gl     = (struct garbagelist*) &(seseRec[1]);
576           struct garbagelist* glroot = gl;
577
578           updateAscendantSESE( seseRec );
579   
580           while( gl != NULL ) {
581             int k;
582             for( k = 0; k < gl->size; k++ ) {
583               void* orig = gl->array[k];
584               ENQUEUE( orig, gl->array[k] );
585             }
586             gl = gl->next;
587           } 
588         
589         // we only have to move across the nodes
590         // of the deque if the top and bottom are
591         // not the same already
592           di=di->next;
593       } while( di !=NULL) ;
594     }
595   }    
596 #else
597   {
598     int        i;
599     deque*     dq;
600     dequeNode* botNode;
601     int        botIndx;
602     dequeNode* topNode;
603     int        topIndx;
604     dequeNode* n;
605     int        j;
606     int        jLo;
607     int        jHi;
608     
609     // goes over ready-to-run SESEs
610     for( i = 0; i < numWorkSchedWorkers; ++i ) {
611       dq = &(deques[i]);
612       
613       botNode = dqDecodePtr( dq->bottom );
614       botIndx = dqDecodeIdx( dq->bottom );
615       
616       topNode = dqDecodePtr( dq->top );
617       topIndx = dqDecodeIdx( dq->top );
618       
619       
620       n = botNode;
621       do {
622         // check all the relevant indices of this
623         // node in the deque, noting if we are in
624         // the top/bottom node which can be partially
625         // full
626         if( n == botNode ) { jLo = botIndx; } else { jLo = 0; }
627         if( n == topNode ) { jHi = topIndx; } else { jHi = DQNODE_ARRAYSIZE; }
628         
629         for( j = jLo; j < jHi; ++j ) {
630           
631           // WHAT?
632           //SESEcommon* common = (SESEcommon*) n->itsDataArr[j];
633           //if(common==seseCommon){
634           //  continue;
635           //}
636           
637           SESEcommon* seseRec = (SESEcommon*) n->itsDataArr[j];
638           
639           struct garbagelist* gl     = (struct garbagelist*) &(seseRec[1]);
640           struct garbagelist* glroot = gl;
641           
642           updateAscendantSESE( seseRec );
643           
644           while( gl != NULL ) {
645             int k;
646             for( k = 0; k < gl->size; k++ ) {
647               void* orig = gl->array[k];
648               ENQUEUE( orig, gl->array[k] );
649             }
650             gl = gl->next;
651           }
652         }
653         
654         // we only have to move across the nodes
655         // of the deque if the top and bottom are
656         // not the same already
657         if( botNode != topNode ) {
658           n = n->next;
659         }
660       } while( n != topNode );
661     }
662   }
663 #endif
664 #endif
665
666
667   while(moreItems()) {
668     void * ptr=dequeue();
669     void *cpy=ptr;
670     int type=((int *)cpy)[0];
671     unsigned INTPTR * pointer;
672 #ifdef TASK
673     if(type==TAGTYPE) {
674       /* Enqueue Tag */
675       /* Nothing is inside */
676       enqueuetag(ptr);
677       continue;
678     }
679 #endif
680     pointer=pointerarray[type];
681     if (pointer==0) {
682       /* Array of primitives */
683       /* Do nothing */
684 #if defined(DSTM)||defined(FASTCHECK)
685       struct ArrayObject *ao=(struct ArrayObject *) ptr;
686       struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
687       ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
688       ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
689 #endif
690 #if defined(STM)
691       struct ArrayObject *ao=(struct ArrayObject *) ptr;
692       struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
693       SENQUEUE((void *)ao->___objlocation___, *((void **)&ao_cpy->___objlocation___));
694 #endif
695     } else if (((INTPTR)pointer)==1) {
696       /* Array of pointers */
697       struct ArrayObject *ao=(struct ArrayObject *) ptr;
698       struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
699 #if (defined(DSTM)||defined(FASTCHECK))
700       ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
701       ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
702 #endif
703 #if defined(STM)
704       SENQUEUE((void *)ao->___objlocation___, *((void **)&ao_cpy->___objlocation___));
705 #endif
706       int length=ao->___length___;
707       int i;
708       for(i=0; i<length; i++) {
709         void *objptr=((void **)(((char *)&ao->___length___)+sizeof(int)))[i];
710         ENQUEUE(objptr, ((void **)(((char *)&ao_cpy->___length___)+sizeof(int)))[i]);
711       }
712     } else {
713       INTPTR size=pointer[0];
714       int i;
715       for(i=1; i<=size; i++) {
716         unsigned int offset=pointer[i];
717         void * objptr=*((void **)(((char *)ptr)+offset));
718         ENQUEUE(objptr, *((void **)(((char *)cpy)+offset)));
719       }
720     }
721   }
722 #ifdef TASK
723   fixtags();
724 #endif
725
726 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
727   needtocollect=0;
728   pthread_mutex_unlock(&gclistlock);
729 #endif
730 }
731
732 #ifdef TASK
733 /* Fix up the references from tags.  This can't be done earlier,
734    because we don't want tags to keep objects alive */
735 void fixtags() {
736   while(taghead!=NULL) {
737     int i;
738     struct pointerblock *tmp=taghead->next;
739     for(i=0; i<tagindex; i++) {
740       struct ___TagDescriptor___ *tagd=taghead->ptrs[i];
741       struct ___Object___ *obj=tagd->flagptr;
742       struct ___TagDescriptor___ *copy=((struct ___TagDescriptor___**)tagd)[1];
743       if (obj==NULL) {
744         /* Zero object case */
745       } else if (obj->type==-1) {
746         /* Single object case */
747         copy->flagptr=((struct ___Object___**)obj)[1];
748       } else if (obj->type==OBJECTARRAYTYPE) {
749         /* Array case */
750         struct ArrayObject *ao=(struct ArrayObject *) obj;
751         int livecount=0;
752         int j;
753         int k=0;
754         struct ArrayObject *aonew;
755
756         /* Count live objects */
757         for(j=0; j<ao->___cachedCode___; j++) {
758           struct ___Object___ * tobj=ARRAYGET(ao, struct ___Object___ *, j);
759           if (tobj->type==-1)
760             livecount++;
761         }
762
763         livecount=((livecount-1)/OBJECTARRAYINTERVAL+1)*OBJECTARRAYINTERVAL;
764         aonew=(struct ArrayObject *) tomalloc(sizeof(struct ArrayObject)+sizeof(struct ___Object___*)*livecount);
765         memcpy(aonew, ao, sizeof(struct ArrayObject));
766         aonew->type=OBJECTARRAYTYPE;
767         aonew->___length___=livecount;
768         copy->flagptr=aonew;
769         for(j=0; j<ao->___cachedCode___; j++) {
770           struct ___Object___ * tobj=ARRAYGET(ao, struct ___Object___ *, j);
771           if (tobj->type==-1) {
772             struct ___Object___ * tobjcpy=((struct ___Object___**)tobj)[1];
773             ARRAYSET(aonew, struct ___Object___*, k++,tobjcpy);
774           }
775         }
776         aonew->___cachedCode___=k;
777         for(; k<livecount; k++) {
778           ARRAYSET(aonew, struct ___Object___*, k, NULL);
779         }
780       } else {
781         /* No object live anymore */
782         copy->flagptr=NULL;
783       }
784     }
785     free(taghead);
786     taghead=tmp;
787     tagindex=NUMPTRS;
788   }
789 }
790 #endif
791
792 void * tomalloc(int size) {
793   void * ptr=to_heapptr;
794   if ((size&7)!=0)
795     size+=(8-(size%8));
796   to_heapptr+=size;
797   return ptr;
798 }
799
800 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
801 void checkcollect(void * ptr) {
802   stopforgc((struct garbagelist *)ptr);
803   restartaftergc();
804 }
805
806 #ifdef DSTM
807 void checkcollect2(void * ptr) {
808   int ptrarray[]={1, (int)ptr, (int) revertlist};
809   stopforgc((struct garbagelist *)ptrarray);
810   restartaftergc();
811   revertlist=(struct ___Object___*)ptrarray[2];
812 }
813 #endif
814
815 void stopforgc(struct garbagelist * ptr) {
816 #ifdef DELAYCOMP
817   //just append us to the list
818   ptrstack.prev=ptr;
819   ptr=(struct garbagelist *) &ptrstack;
820 #if defined(STMARRAY)&&!defined(DUALVIEW)
821   arraystack.prev=ptr;
822   ptr=(struct garbagelist *) &arraystack;
823 #endif
824 #endif
825 #ifndef MAC
826   litem.stackptr=ptr;
827 #ifdef THREADS
828   litem.locklist=pthread_getspecific(threadlocks);
829 #endif
830 #if defined(STM)||defined(THREADS)||defined(MLP)
831   litem.base=&memorybase;
832 #endif
833 #ifdef STM
834   litem.tc_size=c_size;
835   litem.tc_table=&c_table;
836   litem.tc_list=&c_list;
837   litem.tc_structs=&c_structs;
838   litem.objlist=newobjs;
839 #ifdef STMSTATS
840   litem.lockedlist=lockedobjs;
841 #endif
842 #endif
843 #else
844   //handle MAC
845   struct listitem *litem=pthread_getspecific(litemkey);
846   litem->stackptr=ptr;
847 #ifdef THREADS
848   litem->locklist=pthread_getspecific(threadlocks);
849 #endif
850 #endif
851   pthread_mutex_lock(&gclistlock);
852   listcount++;
853   if ((listcount+1)==threadcount) {
854     //only do wakeup if we are ready to GC
855     pthread_cond_signal(&gccond);
856   }
857   pthread_mutex_unlock(&gclistlock);
858 }
859
860 void restartaftergc() {
861   if (needtocollect) {
862     pthread_mutex_lock(&gclock); // Wait for GC
863     pthread_mutex_unlock(&gclock);
864   }
865   pthread_mutex_lock(&gclistlock);
866   listcount--;
867   pthread_mutex_unlock(&gclistlock);
868 }
869 #endif
870
871 #if defined(STM)||defined(THREADS)||defined(MLP)
872 #define MEMORYBLOCK 65536
873 void * helper(struct garbagelist *, int);
874 void * mygcmalloc(struct garbagelist * stackptr, int size) {
875   if ((size&7)!=0)
876     size=(size&~7)+8;
877   if (memorybase==NULL||size>(memorytop-memorybase)) {
878     int toallocate=(size>MEMORYBLOCK)?size:MEMORYBLOCK;
879     memorybase=helper(stackptr, toallocate);
880     bzero(memorybase, toallocate);
881     memorytop=memorybase+toallocate;
882   }
883   char *retvalue=memorybase;
884   memorybase+=size;
885   return retvalue;
886 }
887
888 void * helper(struct garbagelist * stackptr, int size) {
889 #else
890 void * mygcmalloc(struct garbagelist * stackptr, int size) {
891 #endif
892   void *ptr;
893 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
894   while (pthread_mutex_trylock(&gclock)!=0) {
895     stopforgc(stackptr);
896     restartaftergc();
897   }
898 #endif
899   ptr=curr_heapptr;
900   if ((size&7)!=0)
901     size=(size&~7)+8;
902   curr_heapptr+=size;
903   if (curr_heapptr>curr_heapgcpoint||curr_heapptr<curr_heapbase) {
904     if (curr_heapbase==0) {
905       /* Need to allocate base heap */
906       curr_heapbase=malloc(INITIALHEAPSIZE);
907       if (curr_heapbase==NULL) {
908         printf("malloc failed.  Garbage colletcor couldn't get enough memory.  Try changing heap size.\n");
909         exit(-1);
910       }
911 #if defined(STM)||defined(THREADS)||defined(MLP)
912 #else
913       bzero(curr_heapbase, INITIALHEAPSIZE);
914 #endif
915       curr_heaptop=curr_heapbase+INITIALHEAPSIZE;
916       curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(INITIALHEAPSIZE);
917       curr_heapptr=curr_heapbase+size;
918           
919       to_heapbase=malloc(INITIALHEAPSIZE);
920       if (to_heapbase==NULL) {
921         printf("malloc failed.  Garbage collector couldn't get enough memory.  Try changing heap size.\n");
922         exit(-1);
923       }
924       
925       to_heaptop=to_heapbase+INITIALHEAPSIZE;
926       to_heapptr=to_heapbase;
927       ptr=curr_heapbase;
928 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
929       pthread_mutex_unlock(&gclock);
930 #endif
931       return ptr;
932     }
933
934     /* Grow the to heap if necessary */
935     {
936       INTPTR curr_heapsize=curr_heaptop-curr_heapbase;
937       INTPTR to_heapsize=to_heaptop-to_heapbase;
938       INTPTR last_heapsize=0;
939       if (lastgcsize>0) {
940         last_heapsize=HEAPSIZE(lastgcsize, size);
941         if ((last_heapsize&7)!=0)
942           last_heapsize+=(8-(last_heapsize%8));
943       }
944       if (curr_heapsize>last_heapsize)
945         last_heapsize=curr_heapsize;
946       if (last_heapsize>to_heapsize) {
947         free(to_heapbase);
948         to_heapbase=malloc(last_heapsize);
949         if (to_heapbase==NULL) {
950           printf("Error Allocating enough memory\n");
951           exit(-1);
952         }
953         to_heaptop=to_heapbase+last_heapsize;
954         to_heapptr=to_heapbase;
955       }
956     }
957
958     /* Do our collection */
959     collect(stackptr);
960
961     /* Update stat on previous gc size */
962     lastgcsize=(to_heapptr-to_heapbase)+size;
963
964 #ifdef GARBAGESTATS
965     printf("Garbage collected: Old bytes: %u\n", curr_heapptr-curr_heapbase);
966     printf("New space: %u\n", to_heapptr-to_heapbase);
967     printf("Total space: %u\n", to_heaptop-to_heapbase);
968     {
969       int i;
970       for(i=0;i<MAXSTATS;i++) {
971         if (garbagearray[i]!=0)
972           printf("Type=%d Size=%u\n", i, garbagearray[i]);
973       }
974     }
975 #endif
976     /* Flip to/curr heaps */
977     {
978       void * tmp=to_heapbase;
979       to_heapbase=curr_heapbase;
980       curr_heapbase=tmp;
981
982       tmp=to_heaptop;
983       to_heaptop=curr_heaptop;
984       curr_heaptop=tmp;
985
986       tmp=to_heapptr;
987       curr_heapptr=to_heapptr+size;
988       curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(curr_heaptop-curr_heapbase);
989       to_heapptr=to_heapbase;
990
991       /* Not enough room :(, redo gc */
992       if (curr_heapptr>curr_heapgcpoint) {
993 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
994         pthread_mutex_unlock(&gclock);
995 #endif
996         return mygcmalloc(stackptr, size);
997       }
998
999       bzero(tmp, curr_heaptop-tmp);
1000 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
1001       pthread_mutex_unlock(&gclock);
1002 #endif
1003       return tmp;
1004     }
1005   } else {
1006 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
1007     pthread_mutex_unlock(&gclock);
1008 #endif
1009     return ptr;
1010   }
1011 }
1012
1013 int gc_createcopy(void * orig, void ** copy_ptr) {
1014   if (orig==0) {
1015     *copy_ptr=NULL;
1016     return 0;
1017   } else {
1018     int type=((int *)orig)[0];
1019     if (type==-1) {
1020       *copy_ptr=((void **)orig)[1];
1021       return 0;
1022     }
1023     if (type<NUMCLASSES) {
1024       /* We have a normal object */
1025 #ifdef STM
1026       int size=classsize[type]+sizeof(objheader_t);
1027       void *newobj=tomalloc(size);
1028       memcpy(newobj,((char *) orig)-sizeof(objheader_t), size);
1029       newobj=((char *)newobj)+sizeof(objheader_t);
1030 #else
1031       int size=classsize[type];
1032       void *newobj=tomalloc(size);
1033       memcpy(newobj, orig, size);
1034 #endif
1035 #ifdef GARBAGESTATS
1036       garbagearray[type]+=size;
1037 #endif
1038       ((int *)orig)[0]=-1;
1039       ((void **)orig)[1]=newobj;
1040       *copy_ptr=newobj;
1041       return 1;
1042     } else {
1043       /* We have an array */
1044       struct ArrayObject *ao=(struct ArrayObject *)orig;
1045       int elementsize=classsize[type];
1046       int length=ao->___length___;
1047 #ifdef STM
1048 #ifdef STMARRAY
1049       int basesize=length*elementsize;
1050       basesize=(basesize+LOWMASK)&HIGHMASK;
1051       int versionspace=sizeof(int)*2*(basesize>>INDEXSHIFT);
1052       int size=sizeof(struct ArrayObject)+basesize+sizeof(objheader_t)+versionspace;
1053       void *newobj=tomalloc(size);
1054       memcpy(newobj, ((char*)orig)-sizeof(objheader_t)-versionspace, size);
1055       newobj=((char *)newobj)+sizeof(objheader_t)+versionspace;
1056 #else
1057       int size=sizeof(struct ArrayObject)+length*elementsize+sizeof(objheader_t);
1058       void *newobj=tomalloc(size);
1059       memcpy(newobj, ((char*)orig)-sizeof(objheader_t), size);
1060       newobj=((char *)newobj)+sizeof(objheader_t);
1061 #endif
1062 #else
1063       int size=sizeof(struct ArrayObject)+length*elementsize;
1064       void *newobj=tomalloc(size);
1065       memcpy(newobj, orig, size);
1066 #endif
1067 #ifdef GARBAGESTATS
1068       garbagearray[type]+=size;
1069 #endif
1070       ((int *)orig)[0]=-1;
1071       ((void **)orig)[1]=newobj;
1072       *copy_ptr=newobj;
1073       return 1;
1074     }
1075   }
1076 }
1077
1078 #ifdef MLP
1079 updateForwardList(struct Queue *forwardList, int prevUpdate){
1080
1081   struct QueueItem * fqItem=getHead(forwardList);
1082   while(fqItem!=NULL){
1083     SESEcommon* seseRec = (SESEcommon*)(fqItem->objectptr);
1084     struct garbagelist * gl=(struct garbagelist *)&(seseRec[1]);
1085     if(prevUpdate==TRUE){
1086       updateAscendantSESE(seseRec);     
1087     }
1088     // do something here
1089     while(gl!=NULL) {
1090       int i;
1091       for(i=0; i<gl->size; i++) {
1092         void * orig=gl->array[i];
1093         ENQUEUE(orig, gl->array[i]);
1094       }
1095       gl=gl->next;
1096     }    
1097     // iterate forwarding list of seseRec
1098     struct Queue* fList=&seseRec->forwardList;
1099     updateForwardList(fList,prevUpdate);   
1100     fqItem=getNextQueueItem(fqItem);
1101   }   
1102
1103 }
1104
1105 updateMemoryQueue(SESEcommon* seseParent){
1106   // update memory queue
1107   int i,binidx;
1108   for(i=0; i<seseParent->numMemoryQueue; i++){
1109     MemoryQueue *memoryQueue=seseParent->memoryQueueArray[i];
1110     MemoryQueueItem *memoryItem=memoryQueue->head;
1111     while(memoryItem!=NULL){
1112       if(memoryItem->type==HASHTABLE){
1113         Hashtable *ht=(Hashtable*)memoryItem;
1114         for(binidx=0; binidx<NUMBINS; binidx++){
1115           BinElement *bin=ht->array[binidx];
1116           BinItem *binItem=bin->head;
1117           while(binItem!=NULL){
1118             if(binItem->type==READBIN){
1119               ReadBinItem* readBinItem=(ReadBinItem*)binItem;
1120               int ridx;
1121               for(ridx=0; ridx<readBinItem->index; ridx++){
1122                 REntry *rentry=readBinItem->array[ridx];
1123                 SESEcommon* seseRec = (SESEcommon*)(rentry->seseRec);
1124                 struct garbagelist * gl= (struct garbagelist *)&(seseRec[1]);
1125                 updateAscendantSESE(seseRec);
1126                 while(gl!=NULL) {
1127                   int i;
1128                   for(i=0; i<gl->size; i++) {
1129                     void * orig=gl->array[i];
1130                     ENQUEUE(orig, gl->array[i]);
1131                   }
1132                   gl=gl->next;
1133                 } 
1134               } 
1135             }else{ //writebin
1136               REntry *rentry=((WriteBinItem*)binItem)->val;
1137               SESEcommon* seseRec = (SESEcommon*)(rentry->seseRec);
1138               struct garbagelist * gl= (struct garbagelist *)&(seseRec[1]);
1139               updateAscendantSESE(seseRec);
1140               while(gl!=NULL) {
1141                 int i;
1142                 for(i=0; i<gl->size; i++) {
1143                   void * orig=gl->array[i];
1144                   ENQUEUE(orig, gl->array[i]);
1145                 }
1146                 gl=gl->next;
1147               } 
1148             }
1149             binItem=binItem->next;
1150           }
1151         }
1152       }else if(memoryItem->type==VECTOR){
1153         Vector *vt=(Vector*)memoryItem;
1154         int idx;
1155         for(idx=0; idx<vt->index; idx++){
1156           REntry *rentry=vt->array[idx];
1157           if(rentry!=NULL){
1158             SESEcommon* seseRec = (SESEcommon*)(rentry->seseRec);
1159             struct garbagelist * gl= (struct garbagelist *)&(seseRec[1]);
1160             updateAscendantSESE(seseRec);
1161             while(gl!=NULL) {
1162               int i;
1163               for(i=0; i<gl->size; i++) {
1164                 void * orig=gl->array[i];
1165                 ENQUEUE(orig, gl->array[i]);
1166               }
1167               gl=gl->next;
1168             } 
1169           }
1170         }
1171       }else if(memoryItem->type==SINGLEITEM){
1172         SCC *scc=(SCC*)memoryItem;
1173         REntry *rentry=scc->val;
1174         if(rentry!=NULL){
1175           SESEcommon* seseRec = (SESEcommon*)(rentry->seseRec);
1176           struct garbagelist * gl= (struct garbagelist *)&(seseRec[1]);
1177           updateAscendantSESE(seseRec);
1178           while(gl!=NULL) {
1179             int i;
1180             for(i=0; i<gl->size; i++) {
1181               void * orig=gl->array[i];
1182               ENQUEUE(orig, gl->array[i]);
1183             }
1184             gl=gl->next;
1185           } 
1186         }
1187       }
1188       memoryItem=memoryItem->next;
1189     }
1190   }     
1191  }
1192  
1193  updateAscendantSESE(SESEcommon* seseRec){   
1194   int prevIdx;
1195   for(prevIdx=0; prevIdx<(seseRec->numDependentSESErecords); prevIdx++){
1196     SESEcommon* prevSESE = (SESEcommon*) 
1197       (
1198        ((INTPTR)seseRec) + 
1199        seseRec->offsetToDepSESErecords +
1200        (sizeof(INTPTR)*prevIdx)
1201       );
1202        
1203     if(prevSESE!=NULL){
1204       struct garbagelist * prevgl=(struct garbagelist *)&(((SESEcommon*)(prevSESE))[1]);
1205       while(prevgl!=NULL) {
1206         int i;
1207         for(i=0; i<prevgl->size; i++) {
1208           void * orig=prevgl->array[i];
1209           ENQUEUE(orig, prevgl->array[i]);
1210         }
1211         prevgl=prevgl->next;
1212       } 
1213     }
1214   }
1215   
1216  }
1217 #endif
1218
1219 int within(void *ptr){ //debug function
1220   if(ptr>curr_heapptr || ptr<curr_heapbase){
1221     __asm__ __volatile__ ("int $3");  // breakpoint
1222   }
1223 }