summaryrefslogtreecommitdiff
path: root/hv.c
diff options
context:
space:
mode:
authorFather Chrysostomos <sprout@cpan.org>2010-11-15 16:45:15 -0800
committerFather Chrysostomos <sprout@cpan.org>2010-11-15 16:53:58 -0800
commit47f1cf770212f10b8ffbc1777e95c1dbfe120c9d (patch)
tree88dfa0e7f7814942daef17c9a50d24609f6260cf /hv.c
parent23822bdaac3234cb0c133b1c5f69bef87ed1e7f0 (diff)
downloadperl-47f1cf770212f10b8ffbc1777e95c1dbfe120c9d.tar.gz
Keep MRO caches around during hv_clear
This allows it to delete PL_isarev entries. mro_isa_changed_in only deletes items mentioned in HvMROMETA(hv)->isa, so it must be present.
Diffstat (limited to 'hv.c')
-rw-r--r--hv.c58
1 files changed, 33 insertions, 25 deletions
diff --git a/hv.c b/hv.c
index df3605f03a..c3db1c622c 100644
--- a/hv.c
+++ b/hv.c
@@ -1684,23 +1684,26 @@ S_hfreeentries(pTHX_ HV *hv)
if (SvOOK(hv)) {
HE *entry;
- struct mro_meta *meta;
SvFLAGS(hv) &= ~SVf_OOK; /* Goodbye, aux structure. */
/* What aux structure? */
/* (But we still have a pointer to it in iter.) */
- /* Copy the name to a new aux structure if there is a name. */
- if (iter->xhv_name) {
+ /* Copy the name and MRO stuff to a new aux structure
+ if present. */
+ if (iter->xhv_name || iter->xhv_mro_meta) {
struct xpvhv_aux * const newaux = hv_auxinit(hv);
newaux->xhv_name = iter->xhv_name;
newaux->xhv_name_count = iter->xhv_name_count;
iter->xhv_name = NULL;
+ newaux->xhv_mro_meta = iter->xhv_mro_meta;
+ iter->xhv_mro_meta = NULL;
}
- /* Because we have taken xhv_name out, the only allocated
+ /* Because we have taken xhv_name and
+ xhv_mro_meta out, the only allocated
pointers in the aux structure that might exist are the back-
- reference array, xhv_eiter and the MRO stuff.
+ reference array and xhv_eiter.
*/
/* weak references: if called from sv_clear(), the backrefs
@@ -1752,24 +1755,6 @@ S_hfreeentries(pTHX_ HV *hv)
iter->xhv_riter = -1; /* HvRITER(hv) = -1 */
iter->xhv_eiter = NULL; /* HvEITER(hv) = NULL */
- if((meta = iter->xhv_mro_meta)) {
- if (meta->mro_linear_all) {
- SvREFCNT_dec(MUTABLE_SV(meta->mro_linear_all));
- meta->mro_linear_all = NULL;
- /* This is just acting as a shortcut pointer. */
- meta->mro_linear_current = NULL;
- } else if (meta->mro_linear_current) {
- /* Only the current MRO is stored, so this owns the data.
- */
- SvREFCNT_dec(meta->mro_linear_current);
- meta->mro_linear_current = NULL;
- }
- if(meta->mro_nextmethod) SvREFCNT_dec(meta->mro_nextmethod);
- SvREFCNT_dec(meta->isa);
- Safefree(meta);
- iter->xhv_mro_meta = NULL;
- }
-
/* There are now no allocated pointers in the aux structure. */
}
@@ -1820,12 +1805,14 @@ S_hfreeentries(pTHX_ HV *hv)
else
SvFLAGS(hv) &=~SVf_OOK;
- /* If the hash was actually a symbol table, put the name back. */
+ /* If the hash was actually a symbol table, put the name and MRO
+ caches back. */
if (current_aux) {
struct xpvhv_aux * const aux
= SvOOK(hv) ? HvAUX(hv) : hv_auxinit(hv);
aux->xhv_name = current_aux->xhv_name;
aux->xhv_name_count = current_aux->xhv_name_count;
+ aux->xhv_mro_meta = current_aux->xhv_mro_meta;
}
if (tmp_array) Safefree(tmp_array);
@@ -1865,10 +1852,31 @@ Perl_hv_undef(pTHX_ HV *hv)
hv_name_set(hv, NULL, 0, 0);
}
hfreeentries(hv);
- if ((name = HvNAME(hv))) {
+ if (SvOOK(hv)) {
+ struct xpvhv_aux * const aux = HvAUX(hv);
+ struct mro_meta *meta;
+ if ((name = HvNAME(hv))) {
if (PL_stashcache)
(void)hv_delete(PL_stashcache, name, HvNAMELEN_get(hv), G_DISCARD);
hv_name_set(hv, NULL, 0, 0);
+ }
+ if((meta = aux->xhv_mro_meta)) {
+ if (meta->mro_linear_all) {
+ SvREFCNT_dec(MUTABLE_SV(meta->mro_linear_all));
+ meta->mro_linear_all = NULL;
+ /* This is just acting as a shortcut pointer. */
+ meta->mro_linear_current = NULL;
+ } else if (meta->mro_linear_current) {
+ /* Only the current MRO is stored, so this owns the data.
+ */
+ SvREFCNT_dec(meta->mro_linear_current);
+ meta->mro_linear_current = NULL;
+ }
+ if(meta->mro_nextmethod) SvREFCNT_dec(meta->mro_nextmethod);
+ SvREFCNT_dec(meta->isa);
+ Safefree(meta);
+ aux->xhv_mro_meta = NULL;
+ }
}
SvFLAGS(hv) &= ~SVf_OOK;
Safefree(HvARRAY(hv));