Leopold Toetsch <[EMAIL PROTECTED]> wrote:

> - doesn't use managed memory anymore
> - has now freelist handling

Thinking more about all these stacks, I think we got a problem.
Let's assume this code snippet with this call trace:

.sub _main
  newsub eh, .Exception_Handler, catch   # or .Continuation
  set_eh eh                              # or pass on continuation
                           # (1)
  _func1()                 # (2)

     .sub _func1
     ...
     _func2()              # (3)
     ...
         .sub _func2
         ...
         throw exception   # (4)    or invoke Continuation PMC

  catch:                   # (1')

The PMC register frame stack looks like (assuming a function call does
C<pushtopp>):

    (1) <top>
    (2) P16...P31
    (3) P16...P31
    (4)    --> (1')

Now when the Continuation (or Exception) is invoked in (4) all the
context of (1) is restored into the interpreter's context. Program flow
continues in main but all stack changes (on all stacks) are effectively
discarded--the whole context is reset to main's context.

That means currently: we are leaking PMC register frames (2) and (3) in
this example. But we could leak other register stack frames and user or
pad stack entries too:

  .sub func2
     new_pad 3
     save 10
     ...
     throw

I can seen two ways to get around that:

1) use (again) managed (i.e. Buffer) memory for *all* stacks.
Discarding the stacks is cleaned up by the next DOD+GC run.

2) on invoke()ing a Continuation unwind *all* stacks, that is:
   while (interp->ctx.<stack> != continuation->ctx.<stack>)
     POP(interp->ctx.<stack>

During popping off all intermediate entries until the original state is
reached, these stack entries are put onto the stacks freelist and aren't
lost.

3) I'm missing something and can't count

*But* there are coroutines too, which have additional complications,
like their own register frame stacks.

leo

Reply via email to