develooper Front page | perl.perl6.internals | Postings from November 2004

Re: Continuations, basic blocks, loops and register allocation

Thread Previous | Thread Next
Jeff Clites
November 16, 2004 10:07
Re: Continuations, basic blocks, loops and register allocation
Message ID:
On Nov 15, 2004, at 10:29 AM, Leopold Toetsch wrote:

> Jeff Clites <> wrote:
>> Picture this call stack:
>> 	main --> A --> B --> C --> D --> E
>> The call from D to E uses the "RESUMEABLE" label, and E stores the
>> resulting continuation in a global, and everything up to main returns.
>> Then, main invokes the continuation, and we find ourselves back in D.
>> Now, C, B, and A will return "again", without any compile-time hint.
> That's fine. The return is an expected operation. I don't think that's
> the problem. The error in gc_13 is a call path like:
>    choose() -> try (with_cc) -> fail() ->
>                                         |
>                      (choose again)  <- +     <--+
>                                                  |
>    choose() -> try (with_cc) -> fail() ->        |
>                                         |        |
>                      (choose again)  <- +        |
>                                                  |
>    fail()  --------------------------------------+
> The problem now is not per se the path in main from the two choose()
> calls down to fail is executed more then once (as it's the case with
> multiple returns). The problem is the loop in main. By denoting the 
> loop
> from the call to fail() to the first choose() with some kind of syntax,
> the register allocator does the right thing.

But consider even this simple function:

sub B
	a = 1
	print a
	b = 2
	return b

If something called by foo() captures a continuation, and something 
invokes it after B() returns, then there's a hidden branch, in effect, 
from the return to the print, isn't there? The register allocator could 
decide to use the same register for a and b, but then the "second" 
return from foo() would print 2 instead of 1, which is wrong. And the 
author of B(), of course, may have no idea such a thing would happen, 
so wouldn't be able to supply any syntax to tell the compiler.

I'm just trying to come up with a simpler example, since it seems to me 
that there's a problem any time a function returns, and the last thing 
that executed in that frame wasn't a call to that function. (There's a 
lot going on in the gc_13 example, and I think some of it is 
distracting from the main point.)

But a RESUMABLE label seems like the information that's needed by the 
compiler. But on the other hand in an example like the above, the 
function B() may not be written to expect foo() to be resumed. So, what 
should happen at runtime, if the label is absent? We could declare 
undefined behavior, but that would mean that for defined behavior, 
you'd need the RESUMABLE label all the way up the stack, and Ruby and 
Scheme don't have that syntactic constraint. With Scheme, it's only 
clear from the syntax what's going on locally--but you can invoke a 
continuation far from any call/cc, if that continuation was stored away 
into a variable.


Thread Previous | Thread Next Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at | Group listing | About