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