I want these things to be garbage collected, but DOD doesn't trace the buffer. I can't seem to find a way to mark the frames without making the chunks into PMCs (yuck). Is there a way to do this?
I was about to answer your question when I saw your followup where you answered it yourself.
Thats probably the way I would do it. A continuation can know how to mark everything it closes over, and it doesn't have to be a PMC. The brute force method is to copy the whole pad stack as soon as a register frame is pushed or popped. As long as the stack is tree based (where multiple copies of a set of frames can point to the same parent), you only need to copy the current chunk, not the whole stack, although most of the samples I ran at the time never used more than a single register pad stack chunk (I think it was 16 frames per chunk) so its probably an unnecessary short-cut, just copy all chunks.
The downside to our implementation is in the return continuation case. The common case is to create the continuation that you plan to return with, and you already know there will be no need for copy-on-write in most cases because typically the execution path will return using that continuation, and that will then become the "main" execution context. The original interpreter context and all its associated stacks that existed at the time of the snapshot will usually immediately be readonly orphans as soon as you activate the return continuation (unless you saved the initial main context first). It'd be more optimal to skip marking COW altogether in certain cases.
I think I've just confused myself so I'm sure I lost everyone.
The short of it is: the general case of closing over everything and setting COW on everything for each return continuation is inefficient, because the pattern becomes:
1) Freeze continuation B (mark all stacks COW in A, stacks that B references)
2) Activate return continuation B (replaces old interpreter context/continuation A)
3) Continue execution which inevitably does stack modification and
causes a COPY + CLEAR COW bit on everything in B's now private copy.
B's private copy usually becomes the new "permanent" interpreter
context, until the next continuation (C, etc.) is activated. Taking return continuations over
and over has the effect of repeatedly making the main context readonly.
Without reference counting (ugg) I'm not sure how else to implement continuations correctly and achieve any sort of shortcut to skip copying things. As I said to Dan when I first patched them in; hopefully someone smarter than me would come along and do it better/faster, I only care that it actually _works_, and for now, it doesn't, completely.
Also, good papers on VM design with continuations seemed to be rare 2 yrs ago and I expect they still are.
Now that I've taken you on a 2 mile tangent, back to the topic. I'd be happy to see your patch.
-Melvin