Continuation equality
How much work would it be to make sure that the primitive %call/cc produces the same procedure (in the sense of eq?) when called twice in the same continuation?
At the moment, a new procedure is created at every call: https://github.com/ashinn/chibi-scheme/blob/master/vm.c#L1206
The reason why I am asking is because I would like to implement continuation marks and delimited continuations on top of it, but for this it is important to be able to detect whether the code is in a continuation previously seen.
A related question is whether Chibi can store properties associated to procedures (that is closures).
There are two parts to this: storing the continuation somewhere and determining when we are in the same continuation. I don't have a good idea for the former and am worried about overhead. The latter is a straightforward stack comparison but O(n).
I think it's better to go the other way: make delimited continuations the native construct and implement call/cc on top of that. This is a long-standing TODO that I haven't had time for.
For implementing stable continuation procedures efficiently: When SEXP_OP_CALLCC is executed for the first time in a context, make the frame that is stored at the beginning of the cited source code lines special. In this frame, the created continuation procedure is stored. When SEXP_OP_CALLCC is executed the second time in the same context, it detects the special frame at the top of the stack and just reuses the continuation procedure stored there.
Even without delimited continuations, it would be very nice to have as it would, for example, allow one to test whether code is actually executed in tail position (which is guaranteed by many standard procedures), namely just by comparing two continuations.
The most straightforward way to make the frame special is to include an extra offset in every frame, initially null, which contains the continuation. Unfortunately this adds (small) overhead to every non-tail-call.
Out-of-band approaches to storing the information get very complicated, e.g. a map of frame pointer to continuation stored in every stack object. call/cc would create the continuation and add it to the map, and push code onto the stack to remove the map entry.
If reserving space in every frame is too costly, one could store the created continuation procedure on the stack before the actual frame is created. In that actual frame, the IP is a special one, pointing to bytecode that pops the continuation procedure from the stack and resumes execution by calling it. Comparing the stored IP with the special one gives the information whether we are in a frame that has already executed %call/cc.