develooper Front page | perl.perl5.porters | Postings from January 2008

parallel assignment optimization not always right

Thread Next
Matthijs van Duin
January 6, 2008 11:31
parallel assignment optimization not always right
Message ID:
The OPpASSIGN_COMMON flag in list-assignment is supposed to be set when 
perl knows for sure there are no common SVs in the left and right hand 
side lists, so it doesn't need to copy the RHS list before doing any 

Only problem is... the logic entirely forgets about aliasing:

perl -wle '*d=*a; ($c,$d)=(1,2); ($a,$b)=($c,$d); print "$a $b"'

prints "1 1" instead of the expected "1 2".

And it also forgets that unexpected things can happen if lhs SVs have 
set-magic that cause the rhs SVs to change, or if rhs SVs have get-magic 
that depends on the old value of the lhs SVs.

At the same time, it doesn't catch many common cases where doing 
sequential assignment certainly *is* safe, like:

   my ($foo, $bar) = @_;
   () = listfun();
   ($var) = listfun();
   @x[1..3] = 1..3;

in all these cases OPpASSIGN_COMMON is set, even though copying the RHS 
list is quite unnecessary.

I think the best case is to forget about cross-checking the LHS and 
RHS, but instead set OPpASSIGN_COMMON unless either the LHS or the RHS 
is "safe for sequential assignment":

The RHS is safe if it consists entirely of things that cannot possibly 
produce something that aliases an lvalue or is getmagical.  This means 
constants, newly introduced lexicals, and built-in functions with 
non-getmagical return value like ref, refgen, ord, sprintf, ... etc.

The LHS is safe if it consists of undefs or newly introduced lexicals, 
optionally followed by a final arbitrary scalar (the assignment to 
which is the last thing that will happen, so it can do whatever it 
wants).  If there's a whole array or hash in the LHS then everything 
after it can be ignored, since the RHS will be exhausted anyway.

A final arbitrary array can also be supported, but then pp_aassign needs 
to be changed to that the "sv = newSVsv(*relem); *(relem++) = sv;" is 
done for all rhs elements before any av_store is done, to make sure all 
reads are done before any setmagic is triggered.  Something similar can 
be done for hashes.  Doing this will make sure:

   @x = EXPR
   %x = EXPR

won't pointlessly copy the rhs.

Matthijs van Duin  --  May the Forth be with you!

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