diff options
author | Father Chrysostomos <sprout@cpan.org> | 2012-11-29 09:08:08 -0800 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2012-11-29 09:11:32 -0800 |
commit | db9306af4ddf47b54fb142041f8f950b1ec18f08 (patch) | |
tree | 2d966d7a75b8edd8f159f089f96b4e9f061395ee /sv.c | |
parent | af5aa9e378e68e5202ada6a61d269e74cc9fe298 (diff) | |
download | perl-db9306af4ddf47b54fb142041f8f950b1ec18f08.tar.gz |
Clear method caches when unwinding local *foo=sub{}
local *foo=sub{} is done in two stages:
• First the local *foo localises the GP (the glob pointer, or list of
slots), setting a flag on the GV.
• Then scalar assignment sees the flag on the GV on the LHS and loca-
lises a single slot.
The slot localisation only stores on the savestack a pointer into the
GP struct and the old value. There is no reference to the GV.
To restore a method properly, we have to have a reference to the GV
when the slot localisation is undone.
So in this commit I have added a new save type, SAVEt_GVSLOT. It is
like SAVEt_GENERIC_SV, except it pushes the GV as well. Currently
it is used only for CVs, but I will need it for HVs and maybe
AVs as well.
It is possible for the unwinding of the slot localisation to affect
only a GV other than the one that is pushed, if glob assignments have
taken place since the local *foo. So we have to check whether the
pointer is inside the GP and use PL_sub_generation++ if it is not.
Diffstat (limited to 'sv.c')
-rw-r--r-- | sv.c | 26 |
1 files changed, 25 insertions, 1 deletions
@@ -3787,7 +3787,23 @@ S_glob_assign_ref(pTHX_ SV *const dstr, SV *const sstr) GvCVGEN(dstr) = 0; /* Switch off cacheness. */ } } - SAVEGENERICSV(*location); + /* SAVEt_GVSLOT takes more room on the savestack and has more + overhead in leave_scope than SAVEt_GENERIC_SV. But for CVs + leave_scope needs access to the GV so it can reset method + caches. We must use SAVEt_GVSLOT whenever the type is + SVt_PVCV, even if the stash is anonymous, as the stash may + gain a name somehow before leave_scope. */ + if (stype == SVt_PVCV) { + /* There is no save_pushptrptrptr. Creating it for this + one call site would be overkill. So inline the ss push + routines here. */ + SSCHECK(4); + SSPUSHPTR(dstr); + SSPUSHPTR(location); + SSPUSHPTR(SvREFCNT_inc(*location)); + SSPUSHUV(SAVEt_GVSLOT); + } + else SAVEGENERICSV(*location); } dref = *location; if (stype == SVt_PVCV && (*location != sref || GvCVGEN(dstr))) { @@ -12610,6 +12626,14 @@ Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param) ptr = POPPTR(ss,ix); TOPPTR(nss,ix) = svp_dup_inc((SV**)ptr, proto_perl);/* XXXXX */ break; + case SAVEt_GVSLOT: /* any slot in GV */ + sv = (const SV *)POPPTR(ss,ix); + TOPPTR(nss,ix) = sv_dup_inc(sv, param); + ptr = POPPTR(ss,ix); + TOPPTR(nss,ix) = svp_dup_inc((SV**)ptr, proto_perl);/* XXXXX */ + sv = (const SV *)POPPTR(ss,ix); + TOPPTR(nss,ix) = sv_dup_inc(sv, param); + break; case SAVEt_HV: /* hash reference */ case SAVEt_AV: /* array reference */ sv = (const SV *) POPPTR(ss,ix); |