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;}