I may have a possible solution. Disclaimer: I do not really understand continuations, so I may be completely wrong.

This idea involves two assumptions:

1. Most Parrot code will not use continuations except for returning.
   (There will be a significant efficiency loss otherwise.)

2. The most expensive part of constructing a continuation is COWing
   the stack, etc.--simply constructing the data structure is cheap.

3. A return continuation may be safely reused if:
   a. It has not been stored externally.
   b. None of the return continuations for subroutines it has called
      (recursively speaking) have been stored externally.
   c. No other continuations have been constructed.

Here's how it works:

A ReturnContinuation is a lightweight version of a normal Continuation; it contains the information needed to create a Continuation, but is not really a continuation itself. Once allocated, a ReturnContinuation is never[1] truly deallocated; if it dies, it's put on a free list, and will be reused if it's needed.

Before a ReturnContinuation may be stored externally (and thus have the possibility of being invoked later), it has to be transformed into a normal Continuation. This will probably require compilers (or IMCC) to insert an extra instruction, but I don't think that'd be too difficult. (A naive way to do it would be to simply emit a second/different instruction whenever P1 is retrieved. It might be possible to make IMCC do this, or even to write this into the 'set' op.)

If a program either creates a normal Continuation or transforms a ReturnContinuation into a normal one, Parrot will automatically turn all currently-live ReturnContinuations into normal Continuations. (How is an unknown, admittedly--perhaps we'll keep a list of currently-live ReturnContinuations, too.) This means that your return continuation may in fact be a real Continuation instead of a ReturnContinuation.

If a ReturnContinuation is invoked without being stored externally (and thus transformed into a real Continuation), it is immediately considered dead, and returns to the free list.

The effect is that the heavy work of constructing real Continuations is deferred until we have a good reason to believe they'll be needed. For programs that never use continuations except for old-fashioned returning, a lot of work is avoided, because ReturnContinuations are faster to construct; for programs that do use continuations, a little extra work is done, because it would have been faster to construct real Continuations in the first place. I suspect this would usually be a win, although it might be wise to give the language compiler a way to say "I know this program will use continuations, so just construct them that way in the first place."


Example:


A calls B, creates ReturnContinuation rA1.
    B calls C, creates ReturnContinuation rB1.
        C invokes ReturnContinuation rB1 to return to B.
    ReturnContinuation rB1 returns to the free list.
    B calls D, creates ReturnContinuation rB2 (ex-rB1?).
        D stores rB2 into Z:
            rB2 becomes a real Continuation.
            rA1 becomes a real Continuation.
        D invokes Continuation rB2 to return.
    Continuation rB2 does *not* return to the free list.
    B calls E, creates ReturnContinuation rB3.
        E invokes ReturnContinuation rB3 to return.
    ReturnContinuation rB3 returns to the free list.
    B invokes Continuation rA1 to return.
Continuation rA1 does *not* return to the free list.
A calls F, creates ReturnContinuation rA2 (ex-rB3?).
    F creates and stores a new Continuation into Y:
        rA2 becomes a real Continuation.
    F invokes rA2 to return.
Continuation rA1 does *not* return to the free list.
A invokes Z--control jumps to the next statement in B after the call to D.


[1] Conceptually, that is. Realistically, it might make sense to do so if you have a few thousand spare return continuations floating around.


--
Brent "Dax" Royal-Gordon <[EMAIL PROTECTED]>
Perl and Parrot hacker

Oceania has always been at war with Eastasia.

Reply via email to