really, really nasty bug...see page 8-9 of vol 3A of intel processor manual for x86...
[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 volatile 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     if (listptr->seseCommon!=NULL) {
440       updateForwardList(&((SESEcommon*)listptr->seseCommon)->forwardList,FALSE);
441       updateMemoryQueue((SESEcommon*)(listptr->seseCommon));
442     }
443 #endif
444     stackptr=listptr->stackptr;
445     listptr=listptr->next;
446   } else
447     break;
448 }
449 }
450 #endif
451
452 #ifdef FASTCHECK
453   ENQUEUE(___fcrevert___, ___fcrevert___);
454 #endif
455
456 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
457   {
458     int i;
459     stackptr=(struct garbagelist *)global_defs_p;
460     for(i=0; i<stackptr->size; i++) {
461       void * orig=stackptr->array[i];
462       ENQUEUE(orig, stackptr->array[i]);
463     }
464   }
465 #endif
466
467 #ifdef TASK
468   {
469     /* Update objectsets */
470     int i;
471     for(i=0; i<NUMCLASSES; i++) {
472 #if !defined(MULTICORE)
473       struct parameterwrapper * p=objectqueues[i];
474       while(p!=NULL) {
475         struct ObjectHash * set=p->objectset;
476         struct ObjectNode * ptr=set->listhead;
477         while(ptr!=NULL) {
478           void *orig=(void *)ptr->key;
479           ENQUEUE(orig, *((void **)(&ptr->key)));
480           ptr=ptr->lnext;
481         }
482         ObjectHashrehash(set); /* Rehash the table */
483         p=p->next;
484       }
485 #endif
486     }
487   }
488
489 #ifndef FASTCHECK
490   if (forward!=NULL) {
491     struct cnode * ptr=forward->listhead;
492     while(ptr!=NULL) {
493       void * orig=(void *)ptr->key;
494       ENQUEUE(orig, *((void **)(&ptr->key)));
495       ptr=ptr->lnext;
496     }
497     crehash(forward); /* Rehash the table */
498   }
499
500   if (reverse!=NULL) {
501     struct cnode * ptr=reverse->listhead;
502     while(ptr!=NULL) {
503       void *orig=(void *)ptr->val;
504       ENQUEUE(orig, *((void**)(&ptr->val)));
505       ptr=ptr->lnext;
506     }
507   }
508 #endif
509
510   {
511     struct RuntimeNode * ptr=fdtoobject->listhead;
512     while(ptr!=NULL) {
513       void *orig=(void *)ptr->data;
514       ENQUEUE(orig, *((void**)(&ptr->data)));
515       ptr=ptr->lnext;
516     }
517   }
518
519   {
520     /* Update current task descriptor */
521     int i;
522     for(i=0; i<currtpd->numParameters; i++) {
523       void *orig=currtpd->parameterArray[i];
524       ENQUEUE(orig, currtpd->parameterArray[i]);
525     }
526
527   }
528
529   /* Update active tasks */
530   {
531     struct genpointerlist * ptr=activetasks->list;
532     while(ptr!=NULL) {
533       struct taskparamdescriptor *tpd=ptr->src;
534       int i;
535       for(i=0; i<tpd->numParameters; i++) {
536         void * orig=tpd->parameterArray[i];
537         ENQUEUE(orig, tpd->parameterArray[i]);
538       }
539       ptr=ptr->inext;
540     }
541     genrehash(activetasks);
542   }
543
544   /* Update failed tasks */
545   {
546     struct genpointerlist * ptr=failedtasks->list;
547     while(ptr!=NULL) {
548       struct taskparamdescriptor *tpd=ptr->src;
549       int i;
550       for(i=0; i<tpd->numParameters; i++) {
551         void * orig=tpd->parameterArray[i];
552         ENQUEUE(orig, tpd->parameterArray[i]);
553       }
554       ptr=ptr->inext;
555     }
556     genrehash(failedtasks);
557   }
558 #endif
559
560 #ifdef MLP
561 #ifdef SQUEUE
562   {
563     int        i;
564     deque*     dq;
565     dequeItem *di;
566     int        j;
567
568     // goes over ready-to-run SESEs
569     for( i = 0; i < numWorkSchedWorkers; ++i ) {
570       dq = &(deques[i]);
571
572       di=dq->head;
573
574       do {
575         // check all the relevant indices of this
576         // node in the deque, noting if we are in
577         // the top/bottom node which can be partially
578         // full
579
580           // WHAT? 
581           //SESEcommon* common = (SESEcommon*) n->itsDataArr[j];
582           //if(common==seseCommon){
583           // skip the current running SESE
584           //  continue;
585           //}
586         di=(dequeItem *) EXTRACTPTR((INTPTR)di);
587         SESEcommon* seseRec = (SESEcommon*) di->work;
588         if (seseRec!=NULL) {
589           struct garbagelist* gl     = (struct garbagelist*) &(seseRec[1]);
590           struct garbagelist* glroot = gl;
591           
592           updateAscendantSESE( seseRec );
593           
594           while( gl != NULL ) {
595             int k;
596             for( k = 0; k < gl->size; k++ ) {
597               void* orig = gl->array[k];
598               ENQUEUE( orig, gl->array[k] );
599             }
600             gl = gl->next;
601           } 
602         }
603         // we only have to move across the nodes
604         // of the deque if the top and bottom are
605         // not the same already
606           di=di->next;
607       } while( di !=NULL) ;
608     }
609   }    
610 #else
611   {
612     int        i;
613     deque*     dq;
614     dequeNode* botNode;
615     int        botIndx;
616     dequeNode* topNode;
617     int        topIndx;
618     dequeNode* n;
619     int        j;
620     int        jLo;
621     int        jHi;
622     
623     // goes over ready-to-run SESEs
624     for( i = 0; i < numWorkSchedWorkers; ++i ) {
625       dq = &(deques[i]);
626       
627       botNode = dqDecodePtr( dq->bottom );
628       botIndx = dqDecodeIdx( dq->bottom );
629       
630       topNode = dqDecodePtr( dq->top );
631       topIndx = dqDecodeIdx( dq->top );
632       
633       
634       n = botNode;
635       do {
636         // check all the relevant indices of this
637         // node in the deque, noting if we are in
638         // the top/bottom node which can be partially
639         // full
640         if( n == botNode ) { jLo = botIndx; } else { jLo = 0; }
641         if( n == topNode ) { jHi = topIndx; } else { jHi = DQNODE_ARRAYSIZE; }
642         
643         for( j = jLo; j < jHi; ++j ) {
644           
645           // WHAT?
646           //SESEcommon* common = (SESEcommon*) n->itsDataArr[j];
647           //if(common==seseCommon){
648           //  continue;
649           //}
650           
651           SESEcommon* seseRec = (SESEcommon*) n->itsDataArr[j];
652           
653           struct garbagelist* gl     = (struct garbagelist*) &(seseRec[1]);
654           struct garbagelist* glroot = gl;
655           
656           updateAscendantSESE( seseRec );
657           
658           while( gl != NULL ) {
659             int k;
660             for( k = 0; k < gl->size; k++ ) {
661               void* orig = gl->array[k];
662               ENQUEUE( orig, gl->array[k] );
663             }
664             gl = gl->next;
665           }
666         }
667         
668         // we only have to move across the nodes
669         // of the deque if the top and bottom are
670         // not the same already
671         if( botNode != topNode ) {
672           n = n->next;
673         }
674       } while( n != topNode );
675     }
676   }
677 #endif
678 #endif
679
680
681   while(moreItems()) {
682     void * ptr=dequeue();
683     void *cpy=ptr;
684     int type=((int *)cpy)[0];
685     unsigned INTPTR * pointer;
686 #ifdef TASK
687     if(type==TAGTYPE) {
688       /* Enqueue Tag */
689       /* Nothing is inside */
690       enqueuetag(ptr);
691       continue;
692     }
693 #endif
694     pointer=pointerarray[type];
695     if (pointer==0) {
696       /* Array of primitives */
697       /* Do nothing */
698 #if defined(DSTM)||defined(FASTCHECK)
699       struct ArrayObject *ao=(struct ArrayObject *) ptr;
700       struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
701       ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
702       ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
703 #endif
704 #if defined(STM)
705       struct ArrayObject *ao=(struct ArrayObject *) ptr;
706       struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
707       SENQUEUE((void *)ao->___objlocation___, *((void **)&ao_cpy->___objlocation___));
708 #endif
709     } else if (((INTPTR)pointer)==1) {
710       /* Array of pointers */
711       struct ArrayObject *ao=(struct ArrayObject *) ptr;
712       struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
713 #if (defined(DSTM)||defined(FASTCHECK))
714       ENQUEUE((void *)ao->___nextobject___, *((void **)&ao_cpy->___nextobject___));
715       ENQUEUE((void *)ao->___localcopy___, *((void **)&ao_cpy->___localcopy___));
716 #endif
717 #if defined(STM)
718       SENQUEUE((void *)ao->___objlocation___, *((void **)&ao_cpy->___objlocation___));
719 #endif
720       int length=ao->___length___;
721       int i;
722       for(i=0; i<length; i++) {
723         void *objptr=((void **)(((char *)&ao->___length___)+sizeof(int)))[i];
724         ENQUEUE(objptr, ((void **)(((char *)&ao_cpy->___length___)+sizeof(int)))[i]);
725       }
726     } else {
727       INTPTR size=pointer[0];
728       int i;
729       for(i=1; i<=size; i++) {
730         unsigned int offset=pointer[i];
731         void * objptr=*((void **)(((char *)ptr)+offset));
732         ENQUEUE(objptr, *((void **)(((char *)cpy)+offset)));
733       }
734     }
735   }
736 #ifdef TASK
737   fixtags();
738 #endif
739
740 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
741   needtocollect=0;
742   pthread_mutex_unlock(&gclistlock);
743 #endif
744 }
745
746 #ifdef TASK
747 /* Fix up the references from tags.  This can't be done earlier,
748    because we don't want tags to keep objects alive */
749 void fixtags() {
750   while(taghead!=NULL) {
751     int i;
752     struct pointerblock *tmp=taghead->next;
753     for(i=0; i<tagindex; i++) {
754       struct ___TagDescriptor___ *tagd=taghead->ptrs[i];
755       struct ___Object___ *obj=tagd->flagptr;
756       struct ___TagDescriptor___ *copy=((struct ___TagDescriptor___**)tagd)[1];
757       if (obj==NULL) {
758         /* Zero object case */
759       } else if (obj->type==-1) {
760         /* Single object case */
761         copy->flagptr=((struct ___Object___**)obj)[1];
762       } else if (obj->type==OBJECTARRAYTYPE) {
763         /* Array case */
764         struct ArrayObject *ao=(struct ArrayObject *) obj;
765         int livecount=0;
766         int j;
767         int k=0;
768         struct ArrayObject *aonew;
769
770         /* Count live objects */
771         for(j=0; j<ao->___cachedCode___; j++) {
772           struct ___Object___ * tobj=ARRAYGET(ao, struct ___Object___ *, j);
773           if (tobj->type==-1)
774             livecount++;
775         }
776
777         livecount=((livecount-1)/OBJECTARRAYINTERVAL+1)*OBJECTARRAYINTERVAL;
778         aonew=(struct ArrayObject *) tomalloc(sizeof(struct ArrayObject)+sizeof(struct ___Object___*)*livecount);
779         memcpy(aonew, ao, sizeof(struct ArrayObject));
780         aonew->type=OBJECTARRAYTYPE;
781         aonew->___length___=livecount;
782         copy->flagptr=aonew;
783         for(j=0; j<ao->___cachedCode___; j++) {
784           struct ___Object___ * tobj=ARRAYGET(ao, struct ___Object___ *, j);
785           if (tobj->type==-1) {
786             struct ___Object___ * tobjcpy=((struct ___Object___**)tobj)[1];
787             ARRAYSET(aonew, struct ___Object___*, k++,tobjcpy);
788           }
789         }
790         aonew->___cachedCode___=k;
791         for(; k<livecount; k++) {
792           ARRAYSET(aonew, struct ___Object___*, k, NULL);
793         }
794       } else {
795         /* No object live anymore */
796         copy->flagptr=NULL;
797       }
798     }
799     free(taghead);
800     taghead=tmp;
801     tagindex=NUMPTRS;
802   }
803 }
804 #endif
805
806 void * tomalloc(int size) {
807   void * ptr=to_heapptr;
808   if ((size&7)!=0)
809     size+=(8-(size%8));
810   to_heapptr+=size;
811   return ptr;
812 }
813
814 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
815 void checkcollect(void * ptr) {
816   stopforgc((struct garbagelist *)ptr);
817   restartaftergc();
818 }
819
820 #ifdef DSTM
821 void checkcollect2(void * ptr) {
822   int ptrarray[]={1, (int)ptr, (int) revertlist};
823   stopforgc((struct garbagelist *)ptrarray);
824   restartaftergc();
825   revertlist=(struct ___Object___*)ptrarray[2];
826 }
827 #endif
828
829 void stopforgc(struct garbagelist * ptr) {
830 #ifdef DELAYCOMP
831   //just append us to the list
832   ptrstack.prev=ptr;
833   ptr=(struct garbagelist *) &ptrstack;
834 #if defined(STMARRAY)&&!defined(DUALVIEW)
835   arraystack.prev=ptr;
836   ptr=(struct garbagelist *) &arraystack;
837 #endif
838 #endif
839 #ifndef MAC
840   litem.stackptr=ptr;
841 #ifdef THREADS
842   litem.locklist=pthread_getspecific(threadlocks);
843 #endif
844 #if defined(STM)||defined(THREADS)||defined(MLP)
845   litem.base=&memorybase;
846 #endif
847 #ifdef STM
848   litem.tc_size=c_size;
849   litem.tc_table=&c_table;
850   litem.tc_list=&c_list;
851   litem.tc_structs=&c_structs;
852   litem.objlist=newobjs;
853 #ifdef STMSTATS
854   litem.lockedlist=lockedobjs;
855 #endif
856 #endif
857 #else
858   //handle MAC
859   struct listitem *litem=pthread_getspecific(litemkey);
860   litem->stackptr=ptr;
861 #ifdef THREADS
862   litem->locklist=pthread_getspecific(threadlocks);
863 #endif
864 #endif
865   pthread_mutex_lock(&gclistlock);
866   listcount++;
867   if ((listcount+1)==threadcount) {
868     //only do wakeup if we are ready to GC
869     pthread_cond_signal(&gccond);
870   }
871   pthread_mutex_unlock(&gclistlock);
872 }
873
874 void restartaftergc() {
875   if (needtocollect) {
876     pthread_mutex_lock(&gclock); // Wait for GC
877     pthread_mutex_unlock(&gclock);
878   }
879   pthread_mutex_lock(&gclistlock);
880   listcount--;
881   pthread_mutex_unlock(&gclistlock);
882 }
883 #endif
884
885 #if defined(STM)||defined(THREADS)||defined(MLP)
886 #define MEMORYBLOCK 65536
887 void * helper(struct garbagelist *, int);
888 void * mygcmalloc(struct garbagelist * stackptr, int size) {
889   if ((size&7)!=0)
890     size=(size&~7)+8;
891   if (memorybase==NULL||size>(memorytop-memorybase)) {
892     int toallocate=(size>MEMORYBLOCK)?size:MEMORYBLOCK;
893     memorybase=helper(stackptr, toallocate);
894     bzero(memorybase, toallocate);
895     memorytop=memorybase+toallocate;
896   }
897   char *retvalue=memorybase;
898   memorybase+=size;
899   return retvalue;
900 }
901
902 void * helper(struct garbagelist * stackptr, int size) {
903 #else
904 void * mygcmalloc(struct garbagelist * stackptr, int size) {
905 #endif
906   void *ptr;
907 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
908   while (pthread_mutex_trylock(&gclock)!=0) {
909     stopforgc(stackptr);
910     restartaftergc();
911   }
912 #endif
913   ptr=curr_heapptr;
914   if ((size&7)!=0)
915     size=(size&~7)+8;
916   curr_heapptr+=size;
917   if (curr_heapptr>curr_heapgcpoint||curr_heapptr<curr_heapbase) {
918     if (curr_heapbase==0) {
919       /* Need to allocate base heap */
920       curr_heapbase=malloc(INITIALHEAPSIZE);
921       if (curr_heapbase==NULL) {
922         printf("malloc failed.  Garbage colletcor couldn't get enough memory.  Try changing heap size.\n");
923         exit(-1);
924       }
925 #if defined(STM)||defined(THREADS)||defined(MLP)
926 #else
927       bzero(curr_heapbase, INITIALHEAPSIZE);
928 #endif
929       curr_heaptop=curr_heapbase+INITIALHEAPSIZE;
930       curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(INITIALHEAPSIZE);
931       curr_heapptr=curr_heapbase+size;
932           
933       to_heapbase=malloc(INITIALHEAPSIZE);
934       if (to_heapbase==NULL) {
935         printf("malloc failed.  Garbage collector couldn't get enough memory.  Try changing heap size.\n");
936         exit(-1);
937       }
938       
939       to_heaptop=to_heapbase+INITIALHEAPSIZE;
940       to_heapptr=to_heapbase;
941       ptr=curr_heapbase;
942 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
943       pthread_mutex_unlock(&gclock);
944 #endif
945       return ptr;
946     }
947
948     /* Grow the to heap if necessary */
949     {
950       INTPTR curr_heapsize=curr_heaptop-curr_heapbase;
951       INTPTR to_heapsize=to_heaptop-to_heapbase;
952       INTPTR last_heapsize=0;
953       if (lastgcsize>0) {
954         last_heapsize=HEAPSIZE(lastgcsize, size);
955         if ((last_heapsize&7)!=0)
956           last_heapsize+=(8-(last_heapsize%8));
957       }
958       if (curr_heapsize>last_heapsize)
959         last_heapsize=curr_heapsize;
960       if (last_heapsize>to_heapsize) {
961         free(to_heapbase);
962         to_heapbase=malloc(last_heapsize);
963         if (to_heapbase==NULL) {
964           printf("Error Allocating enough memory\n");
965           exit(-1);
966         }
967         to_heaptop=to_heapbase+last_heapsize;
968         to_heapptr=to_heapbase;
969       }
970     }
971
972     /* Do our collection */
973     collect(stackptr);
974
975     /* Update stat on previous gc size */
976     lastgcsize=(to_heapptr-to_heapbase)+size;
977
978 #ifdef GARBAGESTATS
979     printf("Garbage collected: Old bytes: %u\n", curr_heapptr-curr_heapbase);
980     printf("New space: %u\n", to_heapptr-to_heapbase);
981     printf("Total space: %u\n", to_heaptop-to_heapbase);
982     {
983       int i;
984       for(i=0;i<MAXSTATS;i++) {
985         if (garbagearray[i]!=0)
986           printf("Type=%d Size=%u\n", i, garbagearray[i]);
987       }
988     }
989 #endif
990     /* Flip to/curr heaps */
991     {
992       void * tmp=to_heapbase;
993       to_heapbase=curr_heapbase;
994       curr_heapbase=tmp;
995
996       tmp=to_heaptop;
997       to_heaptop=curr_heaptop;
998       curr_heaptop=tmp;
999
1000       tmp=to_heapptr;
1001       curr_heapptr=to_heapptr+size;
1002       curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(curr_heaptop-curr_heapbase);
1003       to_heapptr=to_heapbase;
1004
1005       /* Not enough room :(, redo gc */
1006       if (curr_heapptr>curr_heapgcpoint) {
1007 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
1008         pthread_mutex_unlock(&gclock);
1009 #endif
1010         return mygcmalloc(stackptr, size);
1011       }
1012
1013       bzero(tmp, curr_heaptop-tmp);
1014 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
1015       pthread_mutex_unlock(&gclock);
1016 #endif
1017       return tmp;
1018     }
1019   } else {
1020 #if defined(THREADS)||defined(DSTM)||defined(STM)||defined(MLP)
1021     pthread_mutex_unlock(&gclock);
1022 #endif
1023     return ptr;
1024   }
1025 }
1026
1027 int gc_createcopy(void * orig, void ** copy_ptr) {
1028   if (orig==0) {
1029     *copy_ptr=NULL;
1030     return 0;
1031   } else {
1032     int type=((int *)orig)[0];
1033     if (type==-1) {
1034       *copy_ptr=((void **)orig)[1];
1035       return 0;
1036     }
1037     if (type<NUMCLASSES) {
1038       /* We have a normal object */
1039 #ifdef STM
1040       int size=classsize[type]+sizeof(objheader_t);
1041       void *newobj=tomalloc(size);
1042       memcpy(newobj,((char *) orig)-sizeof(objheader_t), size);
1043       newobj=((char *)newobj)+sizeof(objheader_t);
1044 #else
1045       int size=classsize[type];
1046       void *newobj=tomalloc(size);
1047       memcpy(newobj, orig, size);
1048 #endif
1049 #ifdef GARBAGESTATS
1050       garbagearray[type]+=size;
1051 #endif
1052       ((int *)orig)[0]=-1;
1053       ((void **)orig)[1]=newobj;
1054       *copy_ptr=newobj;
1055       return 1;
1056     } else {
1057       /* We have an array */
1058       struct ArrayObject *ao=(struct ArrayObject *)orig;
1059       int elementsize=classsize[type];
1060       int length=ao->___length___;
1061 #ifdef STM
1062 #ifdef STMARRAY
1063       int basesize=length*elementsize;
1064       basesize=(basesize+LOWMASK)&HIGHMASK;
1065       int versionspace=sizeof(int)*2*(basesize>>INDEXSHIFT);
1066       int size=sizeof(struct ArrayObject)+basesize+sizeof(objheader_t)+versionspace;
1067       void *newobj=tomalloc(size);
1068       memcpy(newobj, ((char*)orig)-sizeof(objheader_t)-versionspace, size);
1069       newobj=((char *)newobj)+sizeof(objheader_t)+versionspace;
1070 #else
1071       int size=sizeof(struct ArrayObject)+length*elementsize+sizeof(objheader_t);
1072       void *newobj=tomalloc(size);
1073       memcpy(newobj, ((char*)orig)-sizeof(objheader_t), size);
1074       newobj=((char *)newobj)+sizeof(objheader_t);
1075 #endif
1076 #else
1077       int size=sizeof(struct ArrayObject)+length*elementsize;
1078       void *newobj=tomalloc(size);
1079       memcpy(newobj, orig, size);
1080 #endif
1081 #ifdef GARBAGESTATS
1082       garbagearray[type]+=size;
1083 #endif
1084       ((int *)orig)[0]=-1;
1085       ((void **)orig)[1]=newobj;
1086       *copy_ptr=newobj;
1087       return 1;
1088     }
1089   }
1090 }
1091
1092 #ifdef MLP
1093 updateForwardList(struct Queue *forwardList, int prevUpdate){
1094
1095   struct QueueItem * fqItem=getHead(forwardList);
1096   while(fqItem!=NULL){
1097     SESEcommon* seseRec = (SESEcommon*)(fqItem->objectptr);
1098     struct garbagelist * gl=(struct garbagelist *)&(seseRec[1]);
1099     if(prevUpdate==TRUE){
1100       updateAscendantSESE(seseRec);     
1101     }
1102     // do something here
1103     while(gl!=NULL) {
1104       int i;
1105       for(i=0; i<gl->size; i++) {
1106         void * orig=gl->array[i];
1107         ENQUEUE(orig, gl->array[i]);
1108       }
1109       gl=gl->next;
1110     }    
1111     // iterate forwarding list of seseRec
1112     struct Queue* fList=&seseRec->forwardList;
1113     updateForwardList(fList,prevUpdate);   
1114     fqItem=getNextQueueItem(fqItem);
1115   }   
1116
1117 }
1118
1119 updateMemoryQueue(SESEcommon* seseParent){
1120   // update memory queue
1121   int i,binidx;
1122   for(i=0; i<seseParent->numMemoryQueue; i++){
1123     MemoryQueue *memoryQueue=seseParent->memoryQueueArray[i];
1124     MemoryQueueItem *memoryItem=memoryQueue->head;
1125     while(memoryItem!=NULL){
1126       if(memoryItem->type==HASHTABLE){
1127         Hashtable *ht=(Hashtable*)memoryItem;
1128         for(binidx=0; binidx<NUMBINS; binidx++){
1129           BinElement *bin=ht->array[binidx];
1130           BinItem *binItem=bin->head;
1131           while(binItem!=NULL){
1132             if(binItem->type==READBIN){
1133               ReadBinItem* readBinItem=(ReadBinItem*)binItem;
1134               int ridx;
1135               for(ridx=0; ridx<readBinItem->index; ridx++){
1136                 REntry *rentry=readBinItem->array[ridx];
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             }else{ //writebin
1150               REntry *rentry=((WriteBinItem*)binItem)->val;
1151               SESEcommon* seseRec = (SESEcommon*)(rentry->seseRec);
1152               struct garbagelist * gl= (struct garbagelist *)&(seseRec[1]);
1153               updateAscendantSESE(seseRec);
1154               while(gl!=NULL) {
1155                 int i;
1156                 for(i=0; i<gl->size; i++) {
1157                   void * orig=gl->array[i];
1158                   ENQUEUE(orig, gl->array[i]);
1159                 }
1160                 gl=gl->next;
1161               } 
1162             }
1163             binItem=binItem->next;
1164           }
1165         }
1166       }else if(memoryItem->type==VECTOR){
1167         Vector *vt=(Vector*)memoryItem;
1168         int idx;
1169         for(idx=0; idx<vt->index; idx++){
1170           REntry *rentry=vt->array[idx];
1171           if(rentry!=NULL){
1172             SESEcommon* seseRec = (SESEcommon*)(rentry->seseRec);
1173             struct garbagelist * gl= (struct garbagelist *)&(seseRec[1]);
1174             updateAscendantSESE(seseRec);
1175             while(gl!=NULL) {
1176               int i;
1177               for(i=0; i<gl->size; i++) {
1178                 void * orig=gl->array[i];
1179                 ENQUEUE(orig, gl->array[i]);
1180               }
1181               gl=gl->next;
1182             } 
1183           }
1184         }
1185       }else if(memoryItem->type==SINGLEITEM){
1186         SCC *scc=(SCC*)memoryItem;
1187         REntry *rentry=scc->val;
1188         if(rentry!=NULL){
1189           SESEcommon* seseRec = (SESEcommon*)(rentry->seseRec);
1190           struct garbagelist * gl= (struct garbagelist *)&(seseRec[1]);
1191           updateAscendantSESE(seseRec);
1192           while(gl!=NULL) {
1193             int i;
1194             for(i=0; i<gl->size; i++) {
1195               void * orig=gl->array[i];
1196               ENQUEUE(orig, gl->array[i]);
1197             }
1198             gl=gl->next;
1199           } 
1200         }
1201       }
1202       memoryItem=memoryItem->next;
1203     }
1204   }     
1205  }
1206  
1207  updateAscendantSESE(SESEcommon* seseRec){   
1208   int prevIdx;
1209   for(prevIdx=0; prevIdx<(seseRec->numDependentSESErecords); prevIdx++){
1210     SESEcommon* prevSESE = (SESEcommon*) 
1211       (
1212        ((INTPTR)seseRec) + 
1213        seseRec->offsetToDepSESErecords +
1214        (sizeof(INTPTR)*prevIdx)
1215       );
1216        
1217     if(prevSESE!=NULL){
1218       struct garbagelist * prevgl=(struct garbagelist *)&(((SESEcommon*)(prevSESE))[1]);
1219       while(prevgl!=NULL) {
1220         int i;
1221         for(i=0; i<prevgl->size; i++) {
1222           void * orig=prevgl->array[i];
1223           ENQUEUE(orig, prevgl->array[i]);
1224         }
1225         prevgl=prevgl->next;
1226       } 
1227     }
1228   }
1229   
1230  }
1231 #endif
1232
1233 int within(void *ptr){ //debug function
1234   if(ptr>curr_heapptr || ptr<curr_heapbase){
1235     __asm__ __volatile__ ("int $3");  // breakpoint
1236   }
1237 }