From: Leopold Toetsch <[EMAIL PROTECTED]>
   Date: Thu, 27 Jul 2006 20:50:18 +0200

   Am Donnerstag, 27. Juli 2006 19:44 schrieb Matt Diephouse:
   > Running this gives:
   >
   >    caught
   >    No exception to pop.

   PIR code running on behalf of a vtable (or MMD) function is implemented by 
   entering a secondary runloop (see src/pmc/delegate.pmc). The C code and the 
   extra runloop is acting as a Continuation barrier . . .

Ouch.

   I've experimented some time ago to get at least exceptions working by 
   rewinding runloops also, but have failed so far.

IIUC, this is not even theoretically possible, at least not without
putting heavy constraints on the code that a secondary runloop can
run [2].  Last night I thought about capturing the identity of the
current runloop in each closure, e.g. by adding a C<jmp_buf> to C<struct
Parrot_cont>, so that invoking the closure would return to the runloop
in which it was created.  Then it occurred to me that, once the
secondary runloop exited, invoking the continuation would make Parrot
jump off into never-never land.

   Of course, this also affects calling actions (or dynamic-wind thunks,
or whatever we are calling them this week).  As a result, my "Partial
fix to make closures invoke actions" patch of Wednesday is clearly not
the right thing; please consider it withdrawn.

   There's no way to get full Continuations working around such C code 
barriers, 
   except by *not* entering secondary runloops at all for these cases[1]. This 
   could be achieved by (optionally) returning a new PC for all vtable/MMD 
   functions that is, by changing the internal (C) calling conventions of all 
   the PMC code.

   leo

   [1] we can't avoid that for e.g. custom sort functions, but these are
   special enough that we could restrict these.

I see a solution for simpler cases, that might even work for custom sort
functions, though it's certainly not painless.  Here's what I would like
to do for calling actions:

   In order to call back into bytecode, the C code must set up a call
using the original runloop that invokes more C code on exit in order to
resume the stack rewinding.  This can be done with a C function hook in
the continuation.  Stack rewinding would therefore need to be split up
into a number of thunks that do the rewinding magic, running between
episodes of bytecode:

   T1.  The entrypoint (which could be Continuation:invoke) scans down
the dynamic environment looking for an action to run.  If it finds one,
it sets it up to run, calling T2 when it exits.  If not, call T3
directly.

   T2.  After running an action, we need to look for the next action.
If we find it, set it up to run and call T2 again on exit.  Otherwise,
call T3 directly.

   T3.  We have reached the bottom, and can start scanning up, if
necessary, using the same logic.  (Since at present we don't call
actions on the way up, this is a noop for now.)

   T4.  Having finally gotten to the destination environment, resume
execution from the bytecode pointed to by the sub.

   Keeping track of state between thunk calls would be pretty messy.
Unless the state is garbage-collected, it'd be hard not to leak memory
when the rewinding is aborted because the bytecode happens to call some
other continuation.

   Does this sound sane?

   Beyond that, I have no clue how to rescue the delegate, ParrotClass,
and ParrotObject pmclasses.  In principal, this strategy could be
applied to the general case.  But I find it really hard to imagine
rewriting *every* call to a vtable method to allow for the possibility
that it might call into bytecode . . .

                                        -- Bob Rogers
                                           http://rgrjr.dyndns.org/

[2]  It might be possible for Exception_Handler, being a restricted sort
     of continuation, but I assume that is no longer interesting, as the
     new PDD23 design doesn't use them.

Reply via email to