On Sep 25, 2004, at 10:14 AM, Dan Sugalski wrote:

At 7:43 PM -0700 9/24/04, Jeff Clites wrote:
On Sep 24, 2004, at 7:32 PM, Dan Sugalski wrote:

At 7:28 PM -0700 9/24/04, Jeff Clites wrote:
On Sep 24, 2004, at 6:51 PM, Aaron Sherman wrote:

However, the point is still sound, and that WILL work in P6, as I
understand it.

Hmm, that's too bad--it could be quite an opportunity for optimization, if you could use-and-discard lexical information at compile-time, when you know there's no eval around to need it.

Even if not it's going in anyway. The introspection abilities are more than worth the extra memory that the name hashes use.

It's a compiler issue.

Well... sorta. It's a specification issue.

*Not* having pads of some sort, whether they're dull, bog-simple activation frames which're just arrays, or the more complex ordered hash system we've gone with, makes continuations untenable. You need a stable backing store, otherwise resuming a continuation's a dodgy thing.

Wait--I think we're talking about two different things. I'm talking about optimizing away nested scopes _within_ a sub; for instance, consider:


sub foo
{
        my $x;
        ...
        $x = 2;

        if(blah)
        {
                my $x;
                ...
                $x = 3;

                if(goo)
                {
                        my $x;
                        ...
                        $x = 4;
                }

                ++$x;
        }

        ++$x;
}

At each curly-brace, a new pad needs to be pushed, and something stored into its "x" slot (maybe just a pointer to a PerlReference also stored in a register), and at the end the pad needs to be popped (and presumably, later garbage-collected).

But, if the semantics of your language are such that you can't look up lexical by name, then the fact that all 3 of those variables have the same name doesn't matter--you could change the names to $x, $y, $z, and create code would behave identically. That is, all the consequences of the lexical structure can be worked out at compile-time, and it doesn't need to be preserved at run-time. So a compiler could compile the above into just some register stores and branches--no need to push new lexical pads while inside the body of the sub, and that should be _much_ faster without the pad manipulation overhead. (But if there could be something like eval inside of those "..." sections, then you _do_ have to save it all.)

[And if, for continuations, those registers need to be stored away to something else, that's still only one pad needed per sub, rather than one needed per lexical scope within a sub.]

But by, "It's a compiler issue", I mean that parrot doesn't get to decide if those curly braces are supposed to mean something at runtime--the compiler make the decision as to whether it needs to emit pad-manipulation ops. (And it goes without saying that the compiler is bound by the semantics of the language it's compiling....) As I already said, I'm not arguing that Parrot shouldn't have lexical pads, just that languages with appropriate semantics can benefit greatly in cases where they don't have to use them. (And for example, I believe I've heard of languages which have something like eval, but for which the execution of the eval'd string doesn't occur in the lexical scope where it's invoked, so they never need by-name lookups of lexicals. That's essentially what you'd get in Perl5 if you had "sub myEval { eval $_[0] }", and only ever called myEval, and not eval directly.)

It also makes up-call lexical peeking and modification impossible. This is something Larry's specified Perl 6 code will be able to do.

That is, any routine should be able to inspect the environment of its caller, and modify that environment, regardless of where the caller came from.

If I'm interpreting that correctly, then it may just have the consequence that the Perl6 compiler can perform fewer optimizations than others. (And if the body of a sub can reference and modify lexicals in its caller, then it sounds like they're not really *lexicals*, which is confusing....) Hmm, that also precludes part of what tail-call optimization usually gives you, since you can't "reuse the current stack frame", if the called sub is supposed to be able to look back at the caller's state, so you lose the potential for unbounded recursion. If that's all correct, Perl6 is giving up a lot for that "peeking" feature.


(And I'm less worried about the memory than I am about all of the pushing and popping and by-name stores and lookups, which could optimized away to just register usage.)

There shouldn't be much, if any, pushing and popping for stuff like this, and access to lexical pads should be an O(1) operation. Remember, you know at compile time what lexical variables are in scope which means if you have a data structure which can be accessed by name and index (like, say, the OrderedHash PMC clas...) most, if not all, of the access to lexicals will be by integer index. That access is also likely to be a one-time deal -- since PMCs are all dealt with by pointer you only need to fetch the pointer out of the store (or put it in for a new PMC) once.

Right, exactly--I'm worried about the overhead of setting that all up just in case it's inspected, for each nested scope _within_ a sub. (That is, the bulk of the generated code might use a register to access a variable for ongoing calculations, but you need at least one by-name store per variable to set up the lexical pad.)


It's unlikely that any sub or method's going to find its runtime dominated by the time it takes to store PMC pointers into an array... :)

I dunno, if it's only doing calculations, then it might--stuff that could have JITted down to one machine instruction per line of code, is going to end up allocating a bunch of lexical pads, and doing hash stores into them. Every curly brace within an MD5 implementation in Perl6 will slow it down.


In fact, consider this code (pretend it's Perl6--I'm writing in Perl5 so I don't mess up the syntax):

sub foo
{
        my $i = 0;

        foreach( 1 .. 1000 )
        {
                my $i = 7;
                bar(2);
        }
}

If you can up-look-at-lexicals, then each time through that loop you have to actually create a new lexical for the inner $i, if bar() might be able to create a reference to it (and create a whole new pad, if bar could reference the pad itself). That's unfortunate--ideally you should be able to optimize that into just calling bar(2) a thousand times in a row. Seems like nothing in Perl6 will be able to be optimized.

JEff



Reply via email to