I dislike replying to myself, however, it seems I haven't been clear
enough in describing how I think this (c|sh)ould be implemented.

Let's abstract DoD to the following psuedocode:

   function markalive(p) {
      if(!p.is_alive)
         interpreter->dod_queue.enqueue(p);
   }
   for p in all pmcs
      p.is_alive = false
   for p in rootset
      interpreter->dod_queue.enqueue(p)
   while interpreter->dod_queue.size()
      p = interpreter->dod_queue.dequeue()
      if(p.is_alive) continue
      p.is_alive = true
      if(p.has_special_mark)
         p.mark()
   for p in all pmcs
      if !p.is_alive
         if p.has_destruct
            p.destruct();
         add p to list of free pmcs
   # end

With my proposal, we'd change it to:

   function markalive(p) {
      if(!p.is_alive)
         interpreter->dod_queue.enqueue(p);
   }
   function weakmark(asker, asked_of, cb, cb_info) {
      if(!asked_of.is_alive)
         interpreter->weakref_cnt ++;
         interpreter->weakref_list.push(cb);
         interpreter->weakref_list.push(cb_info);
         interpreter->weakref_list.push(asked_of);
   }
   interpreter->weakref_cnt = 0;
   interpreter->weakref_list = new fast_unsafe_stack;
   for p in all pmcs
      p.is_alive = false
   for p in rootset
      
   q = interpreter's list of objs to sweep
   while( interpreter->dod_queue.size() )
      p = interpreter->dod_queue.dequeue()
      p.is_alive = true;
      if(p.has_special_mark)
         p.mark()
         if( interpreter->weakref_cnt )
            interpreter->weakref_list.push(interpreter->weakref_cnt);
            interpreter->weakref_list.push(p);
            interpreter->weakref_cnt = 0;
   while( interpreter->weakref_list.size() )
      p = interpreter->weakref_list.pop();
      i = interpreter->weakref_list.pop();
      if( !p.is_alive ) {
         while( i-- ) {
            interpreter->weakref_list.pop();
            interpreter->weakref_list.pop();
            interpreter->weakref_list.pop();
         }
      } else {
         while( i-- ) {
            deadobj = interpreter->weakref_list.pop();
            if( deadobj.is_alive ) {
               interpreter->weakref_list.pop();
               interpreter->weakref_list.pop();
            } else {
               cb_extra = interpreter->weakref_list.pop();
               callback = interpreter->weakref_list.pop();
               callback->(p, deadobj, cb_extra);
            }
         }
      }
   }
   free up memory used by interpreter->weakref_list
   interpreter->weakref_list = NULL;
   for p in all pmcs
      if(!p.is_alive) {
         if( p.has_destruct ) p.destruct();
         add p to list of free pmcs
      }
   # end

Notice that the marking phase of dod now does a single extra integer
check in the common case of objects not having weak references; I
believe that this won't be a significant speed penalty.

Further, note that the weakref_list doesn't need to know (record)
anything about the type of the data being stored in it -- push can take
a void*, and pop can return a void*, and if we want an int, we can just
use a cast.

The reason this is safe to do is because it's *only* created by the dod,
and *only* accessed through the weakmark function; since it's not
exposed to *arbitrary* code; there's no chance of it being accessed
incorrectly, since it's not exposed.

If we wanted, it could be defined as follows:
   typedef struct {
      ptrdiff_t * b;
      ptrdiff_t * i;
   } weaklreflist;
   weaklreflist * new_weaklreflist() {
      weaklreflist * list = malloc(sizeof(weaklreflist));
      list->b = malloc(sizeof(ptrdiff_t) * 1024);
      list->b[0] = 0;
      list->i = b;
      return list;
   }
   void wekref_list_push(weaklreflist * list, void* val) {
      if( ++list->i == list->b+1023 ) {
         ptrdiff_t * newb = malloc(sizeof(ptrdiff_t)*1024);
         ptrdiff_t * oldb = list->b;
         newb[0] = (ptrdiff_t)oldb;
         oldb[1023] = (ptrdiff_t)newb;
         list->b = newb;
         list->i = newb + 1;
      }
      *(list->i) = (ptrdiff_t)val;
   }
   void* weakref_list_pop(weaklreflist * list) {
      if( list->i-- == b ) {
         list->b = (ptrdiff_t*)*(list->b);
         list->i = &(list->b[1022]);
      }
      return (void*)*(list->i);
   }
   void free_weakreflist(weakreflist * list) {
      ptrdiff_t * b = list->b, *n;
      assert(list->i == list->b+1);
      assert(list->b[0] == 0);
      do {
         n = (ptrdiff_t*)b[1023];
         free(b);
         b = n;
      } while(b);
      free(list);
   }
[untested, might contain syntax and logical errors]

I used ptrdiff_t instead of void*, since dealing with pointers to void**
always confuses me and makes my head hurt, not to mention making my code
harder for me to read.

-- 
$a=24;split//,240513;s/\B/ => /for@@=qw(ac ab bc ba cb ca
);{push(@b,$a),($a-=6)^=1 for 2..$a/6x--$|;print "[EMAIL PROTECTED]
]\n";((6<=($a-=6))?$a+=$_[$a%6]-$a%6:($a=pop @b))&&redo;}

Reply via email to