On Wed, Jul 09, 2008 at 01:27:29AM -0400, Bob Rogers wrote:
>    What "foo" should do is create a closure and call that:
> 
>       .const .Sub inner = 'inner'
>       inner = newclosure inner
>       inner()

If I understand what you're saying, and then take it to what I see
as its ultimate conclusion, you're basically claiming that every
call to a subroutine involving lexicals requires a newclosure op.
Consider:

    {
        my $x = 1;
        sub foo() { say $x; }
        foo();
    }

In effect this is little different from having 'foo' as an immediate
block.  If we now say that a newclosure op is required to invoke 'foo', 
then that means that the 'foo()' HLL subroutine has to be generated as:

    .local pmc $P0
    $P0 = find_name_not_null 'foo'
    $P0 = newclosure $P0
    $P0()

Of course, for any given subroutine call like 'foo()', the compiler 
tools can't be certain at compile time that 'foo' is in fact a 
Closure PMC, so we really have to generate:

    $P0 = find_name_not_null 'foo'
    $I0 = isa $P0, 'Closure'
    unless $I0 goto xyz
    $P0 = newclosure $P0
  xyz:
    $P0()

That 'isa' step presents a bad design smell to me -- why should we 
have to test every sub for Closure-ness prior to invoking it?  

It all gets worse if I have something like:

    .sub 'abc' :multi('Integer')
        ...
    .end

    .sub 'abc' :multi('String') :outer('xyz')
        ...
    .end

One of these is a Sub PMC, the other is a Closure PMC, and the thing
that is stored under symbol 'abc' is neither -- that's a MultiSub PMC.  
I'm fairly certain I can't do "newclosure" on the MultiSub PMC.  In
fact, the caller doesn't have any way of knowing which sub is going
to be invoked without actually invoking it, so we really can't do a 
'newclosure' on it.

Ultimately I think that Closure PMCs need to be smart enough to take 
a newclosure if they need one at the time they're invoked, rather than 
trying to place that burden on the caller.  (Note that I'm not arguing
that the current implementation is correct -- I'm just describing what
I think a correct implementation will need to do.)  I also think we
probably still need to have a newclosure opcode available to allow
PIR to explicitly say when to take a closure, but I don't think it
should be required in the PIR generated for every HLL subroutine
invocation.

> [...]
> 
>    It may be possible to rescue Patrick's desired behavior by keeping
> track of whether the outer_sub was initialized by newclosure or not.

My 'desired behavior' is simply that we have something that works.  :-)
But I suspect that this means that closure PMCs will have to keep
track of whether they've already been newclosured.

> Personally, I'd prefer if it were always an error to call a closure sub
> directly; implicitly initializing the outer context is bad enough, but
> re-initializing it is worse.  (But we've had this discussion before [1],
> and I was not persuasive.)

Given the examples I listed above, I think we _have_ to provide a way for
Closure PMCs to be invoked directly from PIR, and then either the Closure PMC
vtable_invoke method or IMCC performs whatever context initialization
and/or fixups that are needed to have everything work.

(Also, a reminder that whatever we do to fix this ticket has to keep
RT #56184 working as well.  :-)

Pm

Reply via email to