diff options
author | Father Chrysostomos <sprout@cpan.org> | 2014-09-18 16:10:01 -0700 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2014-09-18 18:20:50 -0700 |
commit | ff2a62e0c8bedade55bf86a22861a2fe06bb0a16 (patch) | |
tree | c049e3257b21cb049fbbda2a41886fcacd5eec5d /scope.c | |
parent | 4a8cd1baba77cafb21681f12b12c120bdd458938 (diff) | |
download | perl-ff2a62e0c8bedade55bf86a22861a2fe06bb0a16.tar.gz |
Skip no-common-vars optimisation for aliases
The ‘no common vars’ optimisation allows perl to copy the values
straight from the rhs to the lhs in a list assignment.
In ($a,$b) = ($c,$d), that means $c gets assigned to $a,
then $d to $b.
If the same variable occurs on both sides of the expression
(($a,$b)=($b,$a)), then it is necessary to make temporary copies of
the variables on the rhs, before assigning them to the left.
If some variables have been aliased to others, then the common vars
detection can be fooled:
*x = *y;
$x = 3;
($x, $z) = (1, $y);
That assigns 1 to $x, and then goes to assign $y to $z, but $y is
the same as $x, which has just been clobbered. So 1 gets assigned
instead of 3.
This commit solves this by recording in each typeglob whether the sca-
lar is an alias of a scalar from elsewhere.
If such a glob is encountered, then the entire expression is ‘tainted’
such that list assignments will assume there might be common vars.
Diffstat (limited to 'scope.c')
-rw-r--r-- | scope.c | 16 |
1 files changed, 16 insertions, 0 deletions
@@ -1226,6 +1226,22 @@ Perl_leave_scope(pTHX_ I32 base) case SAVEt_READONLY_OFF: SvREADONLY_off(ARG0_SV); break; + case SAVEt_GP_ALIASED_SV: { + /* The GP may have been abandoned, leaving the savestack with + the only remaining reference to it. */ + GP * const gp = (GP *)ARG0_PTR; + if (gp->gp_refcnt == 1) { + GV * const gv = (GV *)sv_2mortal(newSV_type(SVt_PVGV)); + GvGP_set(gv,gp); + gp_free(gv); + } + else { + gp->gp_refcnt--; + if (uv >> 8) gp->gp_flags |= GPf_ALIASED_SV; + else gp->gp_flags &= ~GPf_ALIASED_SV; + } + break; + } default: Perl_croak(aTHX_ "panic: leave_scope inconsistency %u", type); } |