bug fixes
[IRC.git] / Robust / src / Runtime / garbage.c
index 8f233fa4c6430332a5e3f2bcddb5a882bef2dd0a..8611dce62cea4a872f95f35651a7227b87013340 100644 (file)
 #include "dmalloc.h"
 #endif
 #ifdef DSTM
-#include "dstm.h"
+#ifdef RECOVERY
+#include <DSTM/interface_recovery/dstm.h>
+#else
+#include <DSTM/interface/dstm.h>
+#endif
 #endif
 #ifdef STM
 #include "tm.h"
 #endif
+#ifdef DELAYCOMP
+#include "delaycomp.h"
+#endif
+
 
 #define NUMPTRS 100
 
-#define INITIALHEAPSIZE 128*1024*1024
-#define GCPOINT(x) ((int)((x)*0.95))
+#define INITIALHEAPSIZE 128*1024*1024L
+#define GCPOINT(x) ((INTPTR)((x)*0.99))
 /* This define takes in how full the heap is initially and returns a new heap size to use */
-#define HEAPSIZE(x,y) ((int)(x+y))*2
+#define HEAPSIZE(x,y) ((INTPTR)(x+y))*2
 
 #ifdef TASK
 extern struct genhashtable * activetasks;
@@ -39,10 +47,18 @@ extern struct ctable *reverse;
 extern struct RuntimeHash *fdtoobject;
 #endif
 
+#ifdef GARBAGESTATS
+#define MAXSTATS 500
+long garbagearray[MAXSTATS];
+#endif
+
 #if defined(THREADS) || defined(DSTM) || defined(STM)
 int needtocollect=0;
 struct listitem * list=NULL;
 int listcount=0;
+#ifndef MAC
+__thread struct listitem litem;
+#endif
 #endif
 
 //Need to check if pointers are transaction pointers
@@ -53,7 +69,7 @@ int listcount=0;
     if (orig>=curr_heapbase&&orig<curr_heaptop) { \
       void *copy; \
       if (gc_createcopy(orig,&copy)) \
-       enqueue(orig);\
+       enqueue(copy);\
       dst=copy; \
     } \
   }
@@ -62,14 +78,14 @@ int listcount=0;
   if (orig>=curr_heapbase&&orig<curr_heaptop) { \
     void *copy; \
     if (gc_createcopy(orig,&copy)) \
-      enqueue(orig);\
+      enqueue(copy);\
     dst=copy; \
   }
 #define SENQUEUE(orig, dst) \
   { \
     void *copy; \
     if (gc_createcopy(orig,&copy)) \
-      enqueue(orig);\
+      enqueue(copy);\
     dst=copy; \
   }
 #elif defined(FASTCHECK)
@@ -77,13 +93,13 @@ int listcount=0;
   if (((unsigned int)orig)!=1) { \
     void *copy; \
     if (gc_createcopy(orig,&copy)) \
-      enqueue(orig);\
+      enqueue(copy);\
     dst=copy; }
 #else
 #define ENQUEUE(orig, dst) \
   void *copy; \
   if (gc_createcopy(orig,&copy)) \
-    enqueue(orig);\
+    enqueue(copy);\
   dst=copy
 #endif
 
@@ -147,14 +163,15 @@ void fixobjlist(struct objlist * ptr) {
   }
 }
 
-void fixtable(chashlistnode_t ** tc_table, unsigned int tc_size) {
-  unsigned int mask=(tc_size<<3)-1;
+void fixtable(chashlistnode_t ** tc_table, chashlistnode_t **tc_list, cliststruct_t **cstr, unsigned int tc_size) {
+  unsigned int mask=(tc_size<<4)-1;
   chashlistnode_t *node=calloc(tc_size, sizeof(chashlistnode_t));
   chashlistnode_t *ptr=*tc_table;
   chashlistnode_t *curr;
   unsigned int i;
   unsigned int index;
   int isfirst;
+  chashlistnode_t *newlist=NULL;
   for(i=0;i<tc_size;i++) {
     curr=&ptr[i];
     isfirst=1;
@@ -172,51 +189,82 @@ void fixtable(chashlistnode_t ** tc_table, unsigned int tc_size) {
        //rewrite transaction cache entry
        void *vptr=curr->val;
        int type=((int *)vptr)[0];
-       unsigned int *pointer=pointerarray[type];
+       unsigned INTPTR *pointer=pointerarray[type];
        if (pointer==0) {
          //array of primitives - do nothing
          struct ArrayObject *ao=(struct ArrayObject *) vptr;
          SENQUEUE((void *)ao->___objlocation___, *((void **)&ao->___objlocation___));
-       } else if (((int)pointer)==1) {
+       } else if (((INTPTR)pointer)==1) {
          //array of pointers
          struct ArrayObject *ao=(struct ArrayObject *) vptr;
          int length=ao->___length___;
          int i;
          SENQUEUE((void *)ao->___objlocation___, *((void **)&ao->___objlocation___));
-         for(i=0; i<length; i++) {
-           void *objptr=((void **)(((char *)&ao->___length___)+sizeof(int)))[i];
-           SENQUEUE(objptr, ((void **)(((char *)&ao->___length___)+sizeof(int)))[i]);
+#ifdef STMARRAY
+         int lowindex=ao->lowindex;
+         int highindex=ao->highindex;
+         int j;
+         for(j=lowindex; j<=highindex; j++) {
+           unsigned int lockval;
+           GETLOCKVAL(lockval, ao, j);
+           if (lockval!=STMNONE) {
+             int lowi=(j<<INDEXSHIFT)/sizeof(void *);
+             int highi=lowi+(INDEXLENGTH/sizeof(void *));
+             for(i=lowi; i<highi;i++) {
+#else
+             for(i=0; i<length; i++) {
+#endif
+               void *objptr=((void **)(((char *)&ao->___length___)+sizeof(int)))[i];
+               SENQUEUE(objptr, ((void **)(((char *)&ao->___length___)+sizeof(int)))[i]);
+             }
+#ifdef STMARRAY
+           }
          }
+#endif
        } else {
-         int size=pointer[0];
+         INTPTR size=pointer[0];
          int i;
          for(i=1; i<=size; i++) {
            unsigned int offset=pointer[i];
-           void * objptr=*((void **)(((int)vptr)+offset));
-           SENQUEUE(objptr, *((void **)(((int)vptr)+offset)));
+           void * objptr=*((void **)(((char *)vptr)+offset));
+           SENQUEUE(objptr, *((void **)(((char *)vptr)+offset)));
          }
        }
       }
 
       next = curr->next;
-      index = (((unsigned int)key) & mask) >>3;
+      index = (((unsigned INTPTR)key) & mask) >>4;
 
-      curr->key=(unsigned int)key;
+      curr->key=key;
       tmp=&node[index];
       // Insert into the new table
       if(tmp->key == 0) {
        tmp->key = curr->key;
        tmp->val = curr->val;
-       if (!isfirst) {
-         free(curr);
-       }
+       tmp->lnext=newlist;
+       newlist=tmp;
       } else if (isfirst) {
-       chashlistnode_t *newnode= calloc(1, sizeof(chashlistnode_t));
+       chashlistnode_t *newnode;
+       if ((*cstr)->num<NUMCLIST) {
+         newnode=&(*cstr)->array[(*cstr)->num];
+         (*cstr)->num++;
+       } else {
+         //get new list
+         cliststruct_t *tcl=calloc(1,sizeof(cliststruct_t));
+         tcl->next=*cstr;
+         *cstr=tcl;
+         newnode=&tcl->array[0];
+         tcl->num=1;
+       }
        newnode->key = curr->key;
        newnode->val = curr->val;
        newnode->next = tmp->next;
+       newnode->lnext=newlist;
+       newlist=newnode;
        tmp->next=newnode;
       } else {
+       curr->lnext=newlist;
+       newlist=curr;
        curr->next=tmp->next;
        tmp->next=curr;
       }
@@ -226,6 +274,7 @@ void fixtable(chashlistnode_t ** tc_table, unsigned int tc_size) {
   }
   free(ptr);
   (*tc_table)=node;
+  (*tc_list)=newlist;
 }
 #endif
 
@@ -250,7 +299,7 @@ void enqueuetag(struct ___TagDescriptor___ *ptr) {
 }
 #endif
 
-#ifdef STM
+#if defined(STM)||defined(THREADS)
 __thread char * memorybase=NULL;
 __thread char * memorytop=NULL;
 #endif
@@ -267,6 +316,22 @@ void collect(struct garbagelist * stackptr) {
     pthread_cond_wait(&gccond, &gclistlock);
   }
 #endif
+#ifdef DELAYCOMP
+  ptrstack.prev=stackptr;
+  stackptr=(struct garbagelist *) &ptrstack;
+#if defined(STMARRAY)&&!defined(DUALVIEW)
+  arraystack.prev=stackptr;
+  stackptr=(struct garbagelist *) &arraystack;
+#endif
+#endif
+
+#ifdef GARBAGESTATS
+  {
+    int i;
+    for(i=0;i<MAXSTATS;i++)
+      garbagearray[i]=0;
+  }
+#endif
 
   if (head==NULL) {
     headindex=0;
@@ -284,11 +349,16 @@ void collect(struct garbagelist * stackptr) {
 
 #ifdef STM
   if (c_table!=NULL) {
-      fixtable(&c_table, c_size);
-      fixobjlist(newobjs);
-      memorybase=NULL;
+    fixtable(&c_table, &c_list, &c_structs, c_size);
+    fixobjlist(newobjs);
+#ifdef STMSTATS
+    fixobjlist(lockedobjs);
+#endif
   }
 #endif
+#if defined(STM)||defined(THREADS)
+  memorybase=NULL;
+#endif
 
   /* Check current stack */
 #if defined(THREADS)||defined(DSTM)||defined(STM)
@@ -307,6 +377,20 @@ void collect(struct garbagelist * stackptr) {
   }
 #if defined(THREADS)||defined(DSTM)||defined(STM)
   /* Go to next thread */
+#ifndef MAC
+  //skip over us
+  if (listptr==&litem) {
+    listptr=listptr->next;
+  }
+#else
+ {
+  struct listitem *litem=pthread_getspecific(litemkey);
+  if (listptr==litem) {
+    listptr=listptr->next;
+  }
+ }
+#endif
+
   if (listptr!=NULL) {
 #ifdef THREADS
     void * orig=listptr->locklist;
@@ -314,10 +398,15 @@ void collect(struct garbagelist * stackptr) {
 #endif
 #ifdef STM
     if ((*listptr->tc_table)!=NULL) {
-      fixtable(listptr->tc_table, listptr->tc_size);
+      fixtable(listptr->tc_table, listptr->tc_list, listptr->tc_structs, listptr->tc_size);
       fixobjlist(listptr->objlist);
-      (*listptr->base)=NULL;
+#ifdef STMSTATS
+      fixobjlist(listptr->lockedlist);
+#endif
     }
+#endif
+#if defined(STM)||defined(THREADS)
+    *(listptr->base)=NULL;
 #endif
     stackptr=listptr->stackptr;
     listptr=listptr->next;
@@ -426,9 +515,9 @@ void collect(struct garbagelist * stackptr) {
 
   while(moreItems()) {
     void * ptr=dequeue();
-    void *cpy=((void **)ptr)[1];
+    void *cpy=ptr;
     int type=((int *)cpy)[0];
-    unsigned int * pointer;
+    unsigned INTPTR * pointer;
 #ifdef TASK
     if(type==TAGTYPE) {
       /* Enqueue Tag */
@@ -452,7 +541,7 @@ void collect(struct garbagelist * stackptr) {
       struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
       SENQUEUE((void *)ao->___objlocation___, *((void **)&ao_cpy->___objlocation___));
 #endif
-    } else if (((int)pointer)==1) {
+    } else if (((INTPTR)pointer)==1) {
       /* Array of pointers */
       struct ArrayObject *ao=(struct ArrayObject *) ptr;
       struct ArrayObject *ao_cpy=(struct ArrayObject *) cpy;
@@ -470,12 +559,12 @@ void collect(struct garbagelist * stackptr) {
        ENQUEUE(objptr, ((void **)(((char *)&ao_cpy->___length___)+sizeof(int)))[i]);
       }
     } else {
-      int size=pointer[0];
+      INTPTR size=pointer[0];
       int i;
       for(i=1; i<=size; i++) {
        unsigned int offset=pointer[i];
-       void * objptr=*((void **)(((int)ptr)+offset));
-       ENQUEUE(objptr, *((void **)(((int)cpy)+offset)));
+       void * objptr=*((void **)(((char *)ptr)+offset));
+       ENQUEUE(objptr, *((void **)(((char *)cpy)+offset)));
       }
     }
   }
@@ -559,73 +648,82 @@ void * tomalloc(int size) {
 
 #if defined(THREADS)||defined(DSTM)||defined(STM)
 void checkcollect(void * ptr) {
-  struct listitem * tmp=stopforgc((struct garbagelist *)ptr);
-  pthread_mutex_lock(&gclock); // Wait for GC
-  restartaftergc(tmp);
-  pthread_mutex_unlock(&gclock);
+  stopforgc((struct garbagelist *)ptr);
+  restartaftergc();
 }
 
 #ifdef DSTM
 void checkcollect2(void * ptr) {
   int ptrarray[]={1, (int)ptr, (int) revertlist};
-  struct listitem * tmp=stopforgc((struct garbagelist *)ptrarray);
-  pthread_mutex_lock(&gclock); // Wait for GC
-  restartaftergc(tmp);
-  pthread_mutex_unlock(&gclock);
+  stopforgc((struct garbagelist *)ptrarray);
+  restartaftergc();
   revertlist=(struct ___Object___*)ptrarray[2];
 }
 #endif
 
-struct listitem * stopforgc(struct garbagelist * ptr) {
-  struct listitem * litem=malloc(sizeof(struct listitem));
+void stopforgc(struct garbagelist * ptr) {
+#ifdef DELAYCOMP
+  //just append us to the list
+  ptrstack.prev=ptr;
+  ptr=(struct garbagelist *) &ptrstack;
+#if defined(STMARRAY)&&!defined(DUALVIEW)
+  arraystack.prev=ptr;
+  ptr=(struct garbagelist *) &arraystack;
+#endif
+#endif
+#ifndef MAC
+  litem.stackptr=ptr;
+#ifdef THREADS
+  litem.locklist=pthread_getspecific(threadlocks);
+#endif
+#if defined(STM)||defined(THREADS)
+  litem.base=&memorybase;
+#endif
+#ifdef STM
+  litem.tc_size=c_size;
+  litem.tc_table=&c_table;
+  litem.tc_list=&c_list;
+  litem.tc_structs=&c_structs;
+  litem.objlist=newobjs;
+#ifdef STMSTATS
+  litem.lockedlist=lockedobjs;
+#endif
+#endif
+#else
+  //handle MAC
+  struct listitem *litem=pthread_getspecific(litemkey);
   litem->stackptr=ptr;
 #ifdef THREADS
   litem->locklist=pthread_getspecific(threadlocks);
 #endif
-#ifdef STM
-  litem->tc_size=c_size;
-  litem->tc_table=&c_table;
-  litem->objlist=newobjs;
-  litem->base=&memorybase;
 #endif
-  litem->prev=NULL;
   pthread_mutex_lock(&gclistlock);
-  litem->next=list;
-  if(list!=NULL)
-    list->prev=litem;
-  list=litem;
   listcount++;
-  pthread_cond_signal(&gccond);
+  if ((listcount+1)==threadcount) {
+    //only do wakeup if we are ready to GC
+    pthread_cond_signal(&gccond);
+  }
   pthread_mutex_unlock(&gclistlock);
-  return litem;
 }
 
-void restartaftergc(struct listitem * litem) {
-  pthread_mutex_lock(&gclistlock);
-#ifdef THREADS
-  pthread_setspecific(threadlocks, litem->locklist);
-#endif
-  if (litem->prev==NULL) {
-    list=litem->next;
-  } else {
-    litem->prev->next=litem->next;
-  }
-  if (litem->next!=NULL) {
-    litem->next->prev=litem->prev;
+void restartaftergc() {
+  if (needtocollect) {
+    pthread_mutex_lock(&gclock); // Wait for GC
+    pthread_mutex_unlock(&gclock);
   }
+  pthread_mutex_lock(&gclistlock);
   listcount--;
   pthread_mutex_unlock(&gclistlock);
-  free(litem);
 }
 #endif
 
-#ifdef STM
+#if defined(STM)||defined(THREADS)
 #define MEMORYBLOCK 65536
 void * helper(struct garbagelist *, int);
 void * mygcmalloc(struct garbagelist * stackptr, int size) {
   if ((size&7)!=0)
     size=(size&~7)+8;
-  if (memorybase==NULL||(memorybase+size)>memorytop) {
+  if (memorybase==NULL||size>(memorytop-memorybase)) {
     int toallocate=(size>MEMORYBLOCK)?size:MEMORYBLOCK;
     memorybase=helper(stackptr, toallocate);
     memorytop=memorybase+toallocate;
@@ -641,26 +739,33 @@ void * mygcmalloc(struct garbagelist * stackptr, int size) {
 #endif
   void *ptr;
 #if defined(THREADS)||defined(DSTM)||defined(STM)
-  if (pthread_mutex_trylock(&gclock)!=0) {
-    struct listitem *tmp=stopforgc(stackptr);
-    pthread_mutex_lock(&gclock);
-    restartaftergc(tmp);
+  while (pthread_mutex_trylock(&gclock)!=0) {
+    stopforgc(stackptr);
+    restartaftergc();
   }
 #endif
   ptr=curr_heapptr;
   if ((size&7)!=0)
     size=(size&~7)+8;
   curr_heapptr+=size;
-  if (curr_heapptr>curr_heapgcpoint) {
+  if (curr_heapptr>curr_heapgcpoint||curr_heapptr<curr_heapbase) {
     if (curr_heapbase==0) {
       /* Need to allocate base heap */
       curr_heapbase=malloc(INITIALHEAPSIZE);
+      if (curr_heapbase==NULL) {
+       printf("malloc failed.  Garbage collector couldn't get enough memory.  Try changing heap size.\n");
+       exit(-1);
+      }
       bzero(curr_heapbase, INITIALHEAPSIZE);
       curr_heaptop=curr_heapbase+INITIALHEAPSIZE;
       curr_heapgcpoint=((char *) curr_heapbase)+GCPOINT(INITIALHEAPSIZE);
       curr_heapptr=curr_heapbase+size;
 
       to_heapbase=malloc(INITIALHEAPSIZE);
+      if (to_heapbase==NULL) {
+       printf("malloc failed.  Garbage collector couldn't get enough memory.  Try changing heap size.\n");
+       exit(-1);
+      }
       to_heaptop=to_heapbase+INITIALHEAPSIZE;
       to_heapptr=to_heapbase;
       ptr=curr_heapbase;
@@ -672,9 +777,9 @@ void * mygcmalloc(struct garbagelist * stackptr, int size) {
 
     /* Grow the to heap if necessary */
     {
-      int curr_heapsize=curr_heaptop-curr_heapbase;
-      int to_heapsize=to_heaptop-to_heapbase;
-      int last_heapsize=0;
+      INTPTR curr_heapsize=curr_heaptop-curr_heapbase;
+      INTPTR to_heapsize=to_heaptop-to_heapbase;
+      INTPTR last_heapsize=0;
       if (lastgcsize>0) {
        last_heapsize=HEAPSIZE(lastgcsize, size);
        if ((last_heapsize&7)!=0)
@@ -704,6 +809,13 @@ void * mygcmalloc(struct garbagelist * stackptr, int size) {
     printf("Garbage collected: Old bytes: %u\n", curr_heapptr-curr_heapbase);
     printf("New space: %u\n", to_heapptr-to_heapbase);
     printf("Total space: %u\n", to_heaptop-to_heapbase);
+    {
+      int i;
+      for(i=0;i<MAXSTATS;i++) {
+       if (garbagearray[i]!=0)
+         printf("Type=%d Size=%u\n", i, garbagearray[i]);
+      }
+    }
 #endif
     /* Flip to/curr heaps */
     {
@@ -742,7 +854,6 @@ void * mygcmalloc(struct garbagelist * stackptr, int size) {
   }
 }
 
-
 int gc_createcopy(void * orig, void ** copy_ptr) {
   if (orig==0) {
     *copy_ptr=NULL;
@@ -764,6 +875,9 @@ int gc_createcopy(void * orig, void ** copy_ptr) {
       int size=classsize[type];
       void *newobj=tomalloc(size);
       memcpy(newobj, orig, size);
+#endif
+#ifdef GARBAGESTATS
+      garbagearray[type]+=size;
 #endif
       ((int *)orig)[0]=-1;
       ((void **)orig)[1]=newobj;
@@ -775,16 +889,28 @@ int gc_createcopy(void * orig, void ** copy_ptr) {
       int elementsize=classsize[type];
       int length=ao->___length___;
 #ifdef STM
+#ifdef STMARRAY
+      int basesize=length*elementsize;
+      basesize=(basesize+LOWMASK)&HIGHMASK;
+      int versionspace=sizeof(int)*2*(basesize>>INDEXSHIFT);
+      int size=sizeof(struct ArrayObject)+basesize+sizeof(objheader_t)+versionspace;
+      void *newobj=tomalloc(size);
+      memcpy(newobj, ((char*)orig)-sizeof(objheader_t)-versionspace, size);
+      newobj=((char *)newobj)+sizeof(objheader_t)+versionspace;
+#else
       int size=sizeof(struct ArrayObject)+length*elementsize+sizeof(objheader_t);
       void *newobj=tomalloc(size);
       memcpy(newobj, ((char*)orig)-sizeof(objheader_t), size);
       newobj=((char *)newobj)+sizeof(objheader_t);
+#endif
 #else
       int size=sizeof(struct ArrayObject)+length*elementsize;
       void *newobj=tomalloc(size);
       memcpy(newobj, orig, size);
 #endif
-
+#ifdef GARBAGESTATS
+      garbagearray[type]+=size;
+#endif
       ((int *)orig)[0]=-1;
       ((void **)orig)[1]=newobj;
       *copy_ptr=newobj;