The old Google Groups will be going away soon, but your browser is incompatible with the new version.
Message from discussion Lexical variables, scratchpads, closures, ...

From:
To:
Cc:
Followup To:
Subject:
 Validation: For verification purposes please type the characters you see in the picture below or the numbers you hear by clicking the accessibility icon.

More options Jul 31 2002, 12:48 pm
Newsgroups: perl.perl6.internals
From: vouil...@pps.jussieu.fr (Jerome Vouillon)
Date: Wed, 31 Jul 2002 18:25:54 +0200
Local: Wed, Jul 31 2002 12:25 pm
Subject: Lexical variables, scratchpads, closures, ...

Let us think a bit about the implementation of lexical variables.

Assignement

First, let us consider how to compile a variable assignement such
as:
\$x = \$y
where both \$x and \$y are lexical variables.  At first, one may think
that this can be compiled simply into a register assignment:
P0 = P1
where P0 and P1 are the PMC registers standing respectively for \$x
and \$y.

But, I we look at the example below, we see that this will not work
in general.
sub foo {
my \$x = 13;
my \$y = 17;
return (sub { print "\$x\n"; },
sub { \$x = \$y; });
}
(\$print, \$assign) = foo();
&\$assign();
&\$print();
nor to the stack frame of the subroutine "foo".  This implies that
variables must be allocated in the heap.

It turns out that PMCs provide the right operations to implement
variables:  we can compile
my \$x = 13;
my \$y = 17;
\$x = \$y
into
new P0, .PerlInt          # Create e new integer variable (\$x)
set P0, 13                # Set its value to 13
new P1, .PerlInt          # Create e new integer variable (\$y)
set P1, 17                # Set its value to 17
set_pmc P0, P1            # Assigns the value of \$y to \$x
("set" invokes the "set_integer_native" method;
"set_pmc" is not implemented yet, but is mentioned in PDD02.)

So, we should really view a PMC not as a Perl value, but
rather as a Perl variable.

:= operator

Actually, things are a bit more complicated if we take the :=
operator into account.  There seems to be two ways to implement it:
- use an "alias" PMC which forward all method calls to another PMC:
the operation "\$x := \$y" would then turns \$x into an "alias" PMC
pointing to \$y;
- implement a variable not as a PMC, but as a heap-allocated pointer
to a PMC.

The first possibility is probably more efficient because we avoid
some memory allocations and indirections, but it is more complex to
implement.  So I will only consider the second one.

We need to allocate an area in the heap for each lexical variable.
Instead of allocating this area one variable at a time, we can
allocate a single "scratchpad" value for all variables of a block:
this is more efficient.

The compiler can keep track of the index of the variables in the
PMCs. (We will probably need some faster opcodes to access the
array: there is no need to perform a method call, nor to do any
bound checking.)

MY

To implement MY, we need to be able to access to a variable by its
name.  For this, the compiler can generate statically a hash mapping
the variable name to its index in the scratchpad.  Then,
MY{"foo"} will look up the index of the variable "foo" in the
hash and use the index to get the variable PMC in the scratchpad.

To access the scratchpad of an outer block, we need a way to move
from a scratchpad to its parent scratchpad.  This is trivial if we
always set the field 0 of a scratchpad to point to its parent

Closures

closure (Sub class).

Then, the exemple

sub foo {
my \$x = 13;
my \$y = 17;
return (sub { print "\$x\n"; },
sub { \$x = \$y; });
}

would be compiled into

foo:  # We assume the closure is in P0
# We extract the parent scratchpad from the closure and put it
# in P1
# We allocate a new scratchpad
new P2, .Array
set P2[0], P1
# We allocate the \$x variable
new P3, .Int
set P3, 13
set P2[1], P3
# We allocate the \$y variable
new P4, .Int
set P4, 13
set P2[2], P4
# We create the first closure
new P5, .Sub
set_code P5, sub1
# We create the second closure
new P6, .Sub
set_code P6, sub2
# We put them into an array
new P0, .Perlarray
set P0[0], P5
set P0[1], P6
# We return the array
ret
sub1: # We assume the closure is in P0
# We extract the parent scratchpad from the closure and put it
# in P1
# We get the \$x variable and put it in P2
set P2, P1[1]
# ... we print the variable value
ret
sub1: # We assume the closure is in P0
# We extract the parent scratchpad from the closure and put it
# in P1
# We get the \$x and \$y variables
set P2, P1[1]
set P3, P1[2]
# We assign the value of \$y to \$x
set_pmc P2, P3
ret

Conclusion

It seems to me that to implement lexical variables, we only need to
implement the set_pmc method and to extend the Sub class so that it
contains both a code pointer and a scratchpad.

In particular, we don't need any special support for scratchpads, at
least for the moment.

What do you think?

-- Jerome