summaryrefslogtreecommitdiff
path: root/scope.c
diff options
context:
space:
mode:
authorFather Chrysostomos <sprout@cpan.org>2014-09-18 16:10:01 -0700
committerFather Chrysostomos <sprout@cpan.org>2014-09-18 18:20:50 -0700
commitff2a62e0c8bedade55bf86a22861a2fe06bb0a16 (patch)
treec049e3257b21cb049fbbda2a41886fcacd5eec5d /scope.c
parent4a8cd1baba77cafb21681f12b12c120bdd458938 (diff)
downloadperl-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.c16
1 files changed, 16 insertions, 0 deletions
diff --git a/scope.c b/scope.c
index db67656de0..a9c73a4309 100644
--- a/scope.c
+++ b/scope.c
@@ -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);
}