#define PL_savestack (vTHX->Isavestack)
#define PL_savestack_ix (vTHX->Isavestack_ix)
#define PL_savestack_max (vTHX->Isavestack_max)
+#define PL_sawalias (vTHX->Isawalias)
#ifndef PL_sawampersand
#define PL_sawampersand (vTHX->Isawampersand)
#endif
#define GvIMPORTED_CV_on(gv) (GvFLAGS(gv) |= GVf_IMPORTED_CV)
#define GvIMPORTED_CV_off(gv) (GvFLAGS(gv) &= ~GVf_IMPORTED_CV)
+#define GPf_ALIASED_SV 1
+
+#define GvALIASED_SV(gv) (GvGPFLAGS(gv) & GPf_ALIASED_SV)
+#define GvALIASED_SV_on(gv) (GvGPFLAGS(gv) |= GPf_ALIASED_SV)
+#define GvALIASED_SV_off(gv) (GvGPFLAGS(gv) &= ~GPf_ALIASED_SV)
+
#ifndef PERL_CORE
# define GvIN_PAD(gv) 0
# define GvIN_PAD_on(gv) NOOP
PERLVAR(I, markstack_ptr, I32 *)
PERLVAR(I, markstack_max, I32 *)
+PERLVARI(I, sawalias, bool, FALSE) /* must enable common-vars
+ pessimisation */
+
#ifdef PERL_HASH_RANDOMIZE_KEYS
#ifdef USE_PERL_PERTURB_KEYS
PERLVARI(I, hash_rand_bits_enabled, U8, 1) /* used to randomize hash stuff 0 == no-random, 1 == random, 2 == determinsitic */
PP(pp_nextstate)
{
PL_curcop = (COP*)PL_op;
+ PL_sawalias = 0;
TAINT_NOT; /* Each statement is presumed innocent */
PL_stack_sp = PL_stack_base + cxstack[cxstack_ix].blk_oldsp;
FREETMPS;
PUSHs(save_scalar(cGVOP_gv));
else
PUSHs(GvSVn(cGVOP_gv));
+ if (GvREFCNT(cGVOP_gv) > 1 || GvALIASED_SV(cGVOP_gv))
+ PL_sawalias = TRUE;
RETURN;
}
{
dSP;
XPUSHs(MUTABLE_SV(cGVOP_gv));
+ if (isGV(cGVOP_gv)
+ && (GvREFCNT(cGVOP_gv) > 1 || GvALIASED_SV(cGVOP_gv)))
+ PL_sawalias = TRUE;
RETURN;
}
* Don't bother if LHS is just an empty hash or array.
*/
- if ( (PL_op->op_private & OPpASSIGN_COMMON)
+ if ( (PL_op->op_private & OPpASSIGN_COMMON || PL_sawalias)
&& (
firstlelem != lastlelem
|| ! ((sv = *firstlelem))
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);
}
#define SAVEt_CLEARPADRANGE 1
#define SAVEt_CLEARSV 2
#define SAVEt_REGCONTEXT 3
-/*** SPARE 4 ***/
-#define SAVEt_ARG0_MAX 4
+#define SAVEt_ARG0_MAX 3
/* one arg */
+#define SAVEt_GP_ALIASED_SV 4
#define SAVEt_BOOL 5
#define SAVEt_COMPILE_WARNINGS 6
#define SAVEt_COMPPAD 7
&& CopSTASH_ne(PL_curcop, GvSTASH(dstr))) {
GvFLAGS(dstr) |= import_flag;
}
+ if (import_flag == GVf_IMPORTED_SV) {
+ if (intro) {
+ dSS_ADD;
+ SS_ADD_PTR(gp_ref(GvGP(dstr)));
+ SS_ADD_UV(SAVEt_GP_ALIASED_SV
+ | cBOOL(GvALIASED_SV(dstr)) << 8);
+ SS_ADD_END(2);
+ }
+ /* Turn off the flag if sref is not referenced elsewhere,
+ even by weak refs. (SvRMAGICAL is a pessimistic check for
+ back refs.) */
+ if (SvREFCNT(sref) <= 2 && !SvRMAGICAL(sref))
+ GvALIASED_SV_off(dstr);
+ else
+ GvALIASED_SV_on(dstr);
+ }
if (stype == SVt_PVHV) {
const char * const name = GvNAME((GV*)dstr);
const STRLEN len = GvNAMELEN(dstr);
ptr = POPPTR(ss,ix);
TOPPTR(nss,ix) = parser_dup((const yy_parser*)ptr, param);
break;
+ case SAVEt_GP_ALIASED_SV:
+ ptr = POPPTR(ss,ix);
+ TOPPTR(nss,ix) = gp_dup((GP *)ptr, param);
+ ((GP *)ptr)->gp_refcnt++;
+ break;
default:
Perl_croak(aTHX_
"panic: ss_dup inconsistency (%"IVdf")", (IV) type);
PL_minus_F = proto_perl->Iminus_F;
PL_doswitches = proto_perl->Idoswitches;
PL_dowarn = proto_perl->Idowarn;
+ PL_sawalias = proto_perl->Isawalias;
#ifdef PERL_SAWAMPERSAND
PL_sawampersand = proto_perl->Isawampersand;
#endif
use warnings;
-plan( tests => 270 );
+plan( tests => 271 );
# type coercion on assignment
$foo = 'foo';
eval { $y->() };
pass "No crash due to CvGV pointing to glob copy in the stash";
+# Aliasing should disable no-common-vars optimisation.
+{
+ *x = *y;
+ $x = 3;
+ ($x, my $z) = (1, $y);
+ is $z, 3, 'list assignment after aliasing [perl #89646]';
+}
+
+
__END__
Perl
Rules