LanX has asked for the wisdom of the Perl Monks concerning the following question:

Hi

I'm trying to understand lvalue subs on the opcode level and would appreciate some help. For the motivation please read Another approach to extend lvalues ?

here the perlcode I want to analyze

my $scalar; test(); sub normal :lvalue { proxy(); } sub proxy :lvalue { $scalar; } sub nlv { my $x="not lvalue" } sub test { nlv(); normal=42; print $scalar; }
and now how the corresponding opcode looks like, I added the original code as comment. *
perl -MO=Concise,-exec,test,normal,proxy,nlv lvalue.pl main::test: 1 <;> nextstate(main 6 concise.pl:16) v # nlv(); 2 <0> pushmark s 3 <#> gv[*nlv] s 4 <1> entersub[t2] vKS/TARG,1 5 <;> nextstate(main 6 concise.pl:17) v # normal=42; 6 <$> const[IV 42] s 7 <0> pushmark s 8 <#> gv[*normal] s 9 <1> entersub[t4] sKRMS*/NO(),TARG,1 a <2> sassign vKS/2 b <;> nextstate(main 6 concise.pl:18) v # print $scalar; c <0> pushmark s d <0> padsv[$scalar:FAKE] l e <@> print sK f <1> leavesub[1 ref] K/REFC,1 main::normal: g <;> nextstate(main 2 concise.pl:5) v # proxy(); h <0> pushmark s i <#> gv[*proxy] s/EARLYCV j <1> rv2cv sK/NO(),1 k <1> entersub[t2] KS/NO(),TARG,1 l <1> leavesublv[1 ref] K/REFC,1 main::proxy: m <;> nextstate(main 3 concise.pl:8) v # $scalar; n <0> padsv[$scalar:FAKE] o <1> leavesublv[1 ref] K/REFC,1 main::nlv: p <;> nextstate(main 4 concise.pl:12) v # my $x="not lvalue" q <$> const[PV "not lvalue"] s r <0> padsv[$x:4,5] sRM*/LVINTRO s <2> sassign sKS/2 t <1> leavesub[1 ref] K/REFC,1

Well I'm still struggling to understand the opcodes, but please look at the lines 6-a and k.

my interpretation is that by assigning a value to a lvalue-sub the steps are:

  1. cache the value
  2. call the lvalue-sub, which returns a var by refrence
  3. assign the cached value to this var

so even on the level of the opcodes the lvaluesub has no chance to know which value will be assigned to the variable he returns ... Correct?

I'm a little bit confused about line j, what means "rv2cv" (it's the first time this happens right before a sub call)?

I googled through perlguts op.c and concise.pod but can't get a sufficient answer...

Thanx Rolf

* I know with 5.10 I wouldn't need to do it manually but I'm sticking on 5.8.8. I have to figure out how to safely install two different perl-versions on the same system, so that I can maintain both with aptitude.

Replies are listed 'Best First'.
Re: Analyzing opcodes of lvalue-subs...
by ikegami (Patriarch) on Nov 21, 2008 at 02:16 UTC

    I'm a little bit confused about line j, what means "rv2cv"?

    I believe rv2cv gets the CV (code value, the code reference) from the specified glob (symbol table entry). Basically, foo() is implemented as something conceptually similar to *{"foo"}{CODE}->().

    You'll find something similar for all other kinds of package variables: rv2sv for scalars, rv2av for arrays, rv2hv for hashes, etc.

    >perl -MO=Concise -e"$s" 4 <@> leave[1 ref] vKP/REFC ->(end) 1 <0> enter ->2 2 <;> nextstate(main 1 -e:1) v ->3 - <1> ex-rv2sv vK/1 ->4 3 <#> gvsv[*s] s ->4 -e syntax OK >perl -MO=Concise -e"@a" 5 <@> leave[1 ref] vKP/REFC ->(end) 1 <0> enter ->2 2 <;> nextstate(main 1 -e:1) v ->3 4 <1> rv2av[t2] vK/1 ->5 3 <#> gv[*a] s ->4 -e syntax OK

    I'm a little bit confused about line j, what means "rv2cv"?

    Opcodes are defined in pp*.c. Search for pp_opcode. pp_rv2cv is in pp.c.

Re: Analyzing opcodes of lvalue-subs...
by ikegami (Patriarch) on Nov 21, 2008 at 02:43 UTC

    so even on the level of the opcodes the lvaluesub has no chance to know which value will be assigned to the variable he returns ... Correct?

    Correct. sassign (in this case) will do the assignment, and only after the sub has been called.

    The value to assign has already been calculated and awaits on the stack, but that doesn't help because the lvalue sub might have been called as foo() += 5; or (foo(), bar()) = (6, 7);.

    call the lvalue-sub, which returns a var by reference

    (My understanding in this area is limited. Take with a grain of salt.)

    Perl doesn't return SVs, it returns pointers to SVs. So technically, values are always returned by reference in Perl. The point of :lvalue is not to cause the sub to return by reference. Flags passed to entersub indicate it's being called as an lvalue. The only thing entersub does with it is tell the last expression evaluated in the sub that's it's called as an lvalue.

    Most expressions already return lvalues. The effect of the flag is usually to create variables that don't already exist. For example, sub f :lvalue { $h{x} } will create both $h (rv2hv) and $h{x} (helem)

    If the lvalue flag wasn't provided, it wouldn't create those variables, so it would return a read-only undef instead of a writable value.

      ikegami & dave, thanks for your very insightful help! 8 )

      it's clear now, that an extension of perl's inner mechanism of lvalue (which is a general one not only restricted to subs) can only be extended by tieing a callback function to the variable.

      reading perlguts I found some slots to add external "magic"-properties to variables.

      "The PERL_MAGIC_ext and PERL_MAGIC_uvar magic types are defined specifically for use by extensions and will not be used by perl itself."

      IMHO this should be much faster than with classical oo-tie, but I'm not sure if there are other extension (*) relying on this mechanism which would interfere and break a "Turbo-Tie" solution ...

      Cheers Rolf

      UPDATES:

      * probably DBI ???

Re: Analyzing opcodes of lvalue-subs...
by dave_the_m (Monsignor) on Nov 21, 2008 at 10:51 UTC
    The detail you're missing is how an lvalue sub returns. An ordinary sub uses the leavesub op, while an lvalue sub uses leavesublv. The main difference between the two is that (oversimplifying a bit), the former makes copies of all the return items on the stack.

    Dave.