On Fri, Aug 02, 2002 at 08:50:27AM -0700, Sean O'Rourke wrote:
> On Fri, 2 Aug 2002, Jerome Vouillon wrote:
> 
> > On Thu, Aug 01, 2002 at 10:57:34AM -0700, Sean O'Rourke wrote:
> > > My naive implementation would have an array of hashes for each sub, with
> > > one entry for each level of scope within.
> >
> > I would use an array of arrays or a linked-list of arrays.  This is
> > hardly more difficult to implement (you just need to keep track of the
> > variable indices during compilation) and the generated code will be a
> > lot more efficient.
> 
> I don't see how you can cope with '%MY' unless you have a hash.  You could
> have a hash in addition to the array, I suppose.

Sure, you need a hash.  But this can be a statically allocated hash,
mapping variable names to indices.

> In any case, Dan has
> promised us some sort of indexed "back-door" access to our hashes, so I
> get the feeling the point is moot -- hashes will be arrays in some sense.

Allocating a hash will certainly remain a lot more expensive than
allocating an array.  And we are going to allocate pads pretty
often...

> > > This is just like the
> > > pad_stack, but implemented using only language features.  (Dynamic)
> > > lexical lookup works its way through this stack.  Static lookups can
> > > probably be resolved to registers, with code inserted to fetch values out
> > > of the pad the first time they are used, and store them back when a scope
> > > is exited.
> 
> > I think it is good enough for the moment to always go through the
> > stack.
> 
> Without performance numbers, this is hard to test, but it can potentially
> turn a single "a = b + c", which is just "add P0, P1, P2" if a, b, and c
> have been referenced, into a hideous five instructions:
> 
>   fetch_lex P0, 'a'   # Because how we store result depends on a's type
>   fetch_lex P1, 'b'
>   fetch_lex P2, 'c'
>   add P0, P1, P2
>   store_lex P0, 'a'

Sure, but this seems to be a non-trivial optimization (I may be
wrong).  I think we should implement a larger part of the language
first.

By the way, the code should probably be:
   fetch_lex P0, 'a'    # Get the PMC of variable 'a'
   fetch_lex P1, 'b'    # Get the PMC of variable 'b'
   fetch_lex P2, 'c'    # Get the PMC of variable 'c'
   add P0, P1, P2       # Add the values contained in the PMC of 'b' and 'c'
                          and store them in the PMC of 'a'

The opcode store_lex is only needed for the operator := (and maybe for
variable initialization).

> > > Returning a closure would make a copy of the scope array, containing
> > > references to the pad hashes (here's where GC makes me happy, and where I
> > > may make the GC unhappy).
> >
> > You don't need to make a copy at this point.  Instead, the copy should
> > happen each time you enter a block containing lexical variables.  (You
> > should also allocate and fill a new pad at this time.)
> 
> Making a copy on every scope entry would solve the problem (the Befunge
> stack-stack metaphor grows stronger!), but I was hoping we could do
> better, since most lexical scopes won't be creating closures.  The more I
> think about it, though, the more complicated that gets.

Note that when you have a loop you need to allocate some fresh lexical
variables at each iteration (so, you need to create a new pad each
time).  Furthermore, you can create loops with callcc, so the piece of
code below could be a loop, if the function foo captures the current
continuation and the function bar resumes it.
    foo();
    do { my $x = ... }
    bar();

> And actually, thanks to %MY and caller.MY, we need a new pad even
> for scopes without lexicals, since they can be inserted later.

I really hope %MY and caller.MY will not be able to extend the lexical
scope: we would get a really huge speed penalty for a feature which
would hardly ever be used.

-- Jerome

Reply via email to