develooper Front page | perl.perl5.porters | Postings from March 2006

Re: how should %^H work with lexical pramas

Thread Previous | Thread Next
Nicholas Clark
March 31, 2006 05:57
Re: how should %^H work with lexical pramas
Message ID:
On Thu, Mar 30, 2006 at 06:42:11PM +0100, Nicholas Clark wrote:
> On Wed, Mar 29, 2006 at 03:15:17PM +0200, Rafael Garcia-Suarez wrote:
> > Nicholas Clark wrote:
> > > And given that you might want to implement your pragma with more than one
> > > level of subroutine, I infer that you might need to get at $^{foo} from
> > > somewhere up your caller's scope. This starts to sound like the correct
> > > hash should be returned as another value from caller.
> > 
> > Just like the warnings bitfield, yes.
> So, basically, if this test passes, user defined lexical pragmas are go:
> use warnings;
> use strict;
> use Test::More tests=>5;
> sub get_dooot {
>     my @results = caller(0);
>     $results[10]->{dooot};
> }
> {
>     is(get_dooot(), undef);
>     BEGIN {
>         $^H{dooot} = 1;
>     }
>         is(get_dooot(), 1);
>     BEGIN {
>         $^H{dooot} = 42;
>     }
>     {
>         {
>             BEGIN {
>                 $^H{dooot} = 6 * 9;
>             }
>             is(get_dooot(), 54);
>         }
>         is(get_dooot(), 6 * 7);
>     }
>     is(get_dooot(), 6 * 7);
> }
> __END__
> ?
> (in that at runtime you can read the value that %^H had in that scope, with
> %^H propagating correctly into blocks, and behaving correctly when redefined
> within a block)

With change 27643 this will pass. To quote op.c:

/* To implement user lexical pragams, there needs to be a way at run time to
   get the compile time state of %^H for that block.  Storing %^H in every
   block (or even COP) would be very expensive, so a different approach is
   taken.  The (running) state of %^H is serialised into a tree of HE-like
   structs.  Stores into %^H are chained onto the current leaf as a struct
   refcounted_he * with the key and the value.  Deletes from %^H are saved
   with a value of PL_sv_placeholder.  The state of %^H at any point can be
   turned back into a regular HV by walking back up the tree from that point's
   leaf, ignoring any key you've already seen (placeholder or now), storing
   the rest into the HV structure, then removing the placeholders. Hence
   memory is only used to store the %^H deltas from the enclosing COP, rather
   than the entire %^H on each COP.
   To cause actions on %^H to write out the serialisation records, it has
   magic type 'H'. This magic (itself) does nothing, but its presence causes
   the values to gain magic type 'h', which has entries for set and clear.
   C<Perl_magic_sethint> updates C<PL_compiling.cop_hints> with a store
   record, with deletes written by C<Perl_magic_clearhint>. C<SAVE_HINTS>
   saves the current C<PL_compiling.cop_hints> on the save stack, so that it
   will be correctly restored when any inner compiling scope is exited.

Current runtime behaviour of %^H is unchanged. I've not tested caller through
evals yet - it may be broken. Others are welcome to write tests while I take
a little break from all this. It may be possible to avoid Robin's trick of
storing %^H away for eval, now that %^H can be recreated.

I'm not sure whether returning the 11th argument from caller should be made
into a (pragma controlled!) feature, as building the hash is potentially
expensive. struct cop now looks like this:

struct cop {
    char *	cop_label;	/* label for this construct */
    char *	cop_stashpv;	/* package line was compiled in */
    char *	cop_file;	/* file name the following line # is from */
    HV *	cop_stash;	/* package line was compiled in */
    GV *	cop_filegv;	/* file the following line # is from */
    U32		cop_seq;	/* parse sequence number */
    I32		cop_arybase;	/* array base this line was compiled with */
    line_t      cop_line;       /* line # of this command */
    SV *	cop_warnings;	/* lexical warnings bitmask */
    SV *	cop_io;		/* lexical IO defaults */
    /* compile time state of %^H.  See the comment in op.c for how this is
       used to recreate a hash to return from caller.  */
    struct refcounted_he * cop_hints;

Two things strike me

1: It might be possible to reduce it back by one pointer by putting it in %^H,
   and accessing it via cop_hints

2: We can probably solve the caller-doesn't-get-all-hints bug by swapping the
   use of op_private and cop_arybase in COP. Currently the 8 bit op_private is
   used to store hints, and cop_arybase stores $[, which typically is 0 or 1.

   So swap them and either restrict $[ to -128 - +127, or store -127 - +127
   in op_private, and use -128 as a flag to dig into cop_hints to find the
   true value.

Nicholas Clark

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