diff options
author | Father Chrysostomos <sprout@cpan.org> | 2012-11-28 18:04:01 -0800 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2012-11-29 09:11:31 -0800 |
commit | 4e52a9b69e39f85d6a5d7ac598c61ff0b00f94ee (patch) | |
tree | 0ad7b7828f9733b88b28a3fed6799beb1492f4af /scope.c | |
parent | 3d460042b1251a4b5e3b583fa6be358554dd3bcc (diff) | |
download | perl-4e52a9b69e39f85d6a5d7ac598c61ff0b00f94ee.tar.gz |
Clear method caches when unwinding local *foo=*method
It was already working for those cases where *foo contained a sub
before and after localisation. For those cases where *foo had no sub
but localised assignment gave it one, method caches were not being
reset on scope exit.
case SAVEt_GP in scope.c:leave_scope needs to look at both GPs (glob
pointer, or list of glob slots), both from before and after the unlo-
calisation. If either has a sub, method caches need to be cleared.
This does not yet fix local *foo = sub {}, but I added a to-do
test for it. (This is more complicated, as localisation happens in
two seperate steps, the glob slot localisation storing no pointers to
the glob itself on the savestack.)
Diffstat (limited to 'scope.c')
-rw-r--r-- | scope.c | 12 |
1 files changed, 8 insertions, 4 deletions
@@ -865,14 +865,18 @@ Perl_leave_scope(pTHX_ I32 base) case SAVEt_GP: /* scalar reference */ ptr = SSPOPPTR; gv = MUTABLE_GV(SSPOPPTR); - gp_free(gv); - GvGP_set(gv, (GP*)ptr); - if ((hv=GvSTASH(gv)) && HvENAME_get(hv)) { + { + /* possibly taking a method out of circulation */ + const bool had_method = !!GvCVu(gv); + gp_free(gv); + GvGP_set(gv, (GP*)ptr); + if ((hv=GvSTASH(gv)) && HvENAME_get(hv)) { if (GvNAMELEN(gv) == 3 && strnEQ(GvNAME(gv), "ISA", 3)) mro_isa_changed_in(hv); - else if (GvCVu(gv)) + else if (had_method || GvCVu(gv)) /* putting a method back into circulation ("local")*/ gv_method_changed(gv); + } } SvREFCNT_dec(gv); break; |