When a glob is deleted, mark its sub as ANON.
Ben Morrow [Sun, 4 Jan 2009 20:04:39 +0000 (20:04 +0000)]
embed.fnc
hv.c

index 439203c..08f7725 100644 (file)
--- a/embed.fnc
+++ b/embed.fnc
@@ -1354,6 +1354,7 @@ paRxo     |void*  |get_arena      |const size_t svtype|const U32 misc
 #if defined(PERL_IN_HV_C) || defined(PERL_DECL_PROT)
 s      |void   |hsplit         |NN HV *hv
 s      |void   |hfreeentries   |NN HV *hv
+s      |I32    |anonymise_cv   |NULLOK const char *stash|NN SV *val
 sa     |HE*    |new_he
 sanR   |HEK*   |save_hek_flags |NN const char *str|I32 len|U32 hash|int flags
 sn     |void   |hv_magic_check |NN HV *hv|NN bool *needs_copy|NN bool *needs_store
diff --git a/hv.c b/hv.c
index ebb10fb..ab22584 100644 (file)
--- a/hv.c
+++ b/hv.c
@@ -1468,8 +1468,8 @@ Perl_hv_free_ent(pTHX_ HV *hv, register HE *entry)
     if (!entry)
        return;
     val = HeVAL(entry);
-    if (val && isGV(val) && isGV_with_GP(val) && GvCVu(val) && HvNAME_get(hv))
-        mro_method_changed_in(hv);     /* deletion of method from stash */
+    if (HvNAME(hv) && anonymise_cv(HvNAME(hv), val) && GvCVu(val))
+       mro_method_changed_in(hv);
     SvREFCNT_dec(val);
     if (HeKLEN(entry) == HEf_SVKEY) {
        SvREFCNT_dec(HeKEY_sv(entry));
@@ -1482,6 +1482,29 @@ Perl_hv_free_ent(pTHX_ HV *hv, register HE *entry)
     del_HE(entry);
 }
 
+static I32
+S_anonymise_cv(const char *stash, SV *val)
+{
+    CV *cv;
+
+    PERL_ARGS_ASSERT_ANONYMISE_CV;
+
+    if (val && isGV(val) && isGV_with_GP(val) && (cv = GvCV(val))) {
+       if ((SV *)CvGV(cv) == val) {
+           SV *gvname;
+           GV *anongv;
+
+           gvname = newSVpvf("%s::__ANON__", stash ? stash : "__ANON__");
+           anongv = gv_fetchsv(gvname, GV_ADDMULTI, SVt_PVCV);
+           SvREFCNT_dec(gvname);
+           CvGV(cv) = anongv;
+           CvANON_on(cv);
+           return 1;
+       }
+    }
+    return 0;
+}
+
 void
 Perl_hv_delayfree_ent(pTHX_ HV *hv, register HE *entry)
 {
@@ -1646,6 +1669,22 @@ S_hfreeentries(pTHX_ HV *hv)
     if (!orig_array)
        return;
 
+    if (HvNAME(hv) && orig_array != NULL) {
+       /* symbol table: make all the contained subs ANON */
+       STRLEN i;
+       XPVHV *xhv = (XPVHV*)SvANY(hv);
+
+       for (i = 0; i <= xhv->xhv_max; i++) {
+           HE *entry = (HvARRAY(hv))[i];
+           for (; entry; entry = HeNEXT(entry)) {
+               SV *val = HeVAL(entry);
+               /* we need to put the subs in the __ANON__ symtable, as
+                * this one is being cleared. */
+               anonymise_cv(NULL, val);
+           }
+       }
+    }
+
     if (SvOOK(hv)) {
        /* If the hash is actually a symbol table with a name, look after the
           name.  */