/* guardians in cinquecento follow the instruction of: R. Kent Dybvig, David Eby, and Carl Bruggeman. Guardians in a generation-based collector. ACM SIGPLAN 1993 Conference on Programming Language Design and Implementation, 207-216, June 1993. http://www.cs.indiana.edu/~dyb/pubs/guardians-pldi93.pdf */ @define postgc() { } /* V comes from the runtime. it is the value of the AC register. by passing and returning it, we preserve it without hand-rolling a call frame in the runtime or some other special mechanism. */ @define callpostgc(v) { postgc(); return v; } @define mkguardian() { @local tc, g; { @local x; x = cons(nil, nil); tc = cons(x, x); } @define g(arg ...) { if(length(arg) == 0){ if(car(tc) == cdr(tc)) return nil; else{ @local x, y; x = car(tc); y = car(x); setcar(tc, cdr(x)); setcar(x, nil); setcdr(x, nil); return y; } }else if(length(arg) == 1) instguard(cons(arg[0], tc)); else error("wrong number of arguments to guardian: %a %d", arg, length(arg)); } return g; } @define finalize(o, fn) { @local origg, _finalize; @local guards, inf, dofinals; inf = 0; // avoid inconsistent access to guards @define _finalize(o, fn) { @local g; g = mkguardian(); g(o); inf = 1; append(guards, cons(g, fn)); inf = 0; return nil; } @define dofinals() { @local ng; if(inf) return; ng = []; foreach(@lambda(p){ @local x; x = car(p)(); if(x == nil) append(ng, p); else cdr(p)(x); }, guards); guards = ng; } guards = []; /* skip this initialization on future finalize calls */ finalize = _finalize; /* schedule finalizer after each gc */ origg = postgc; postgc = @lambda() { origg(); dofinals(); }; return _finalize(o, fn); }