This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
S_hfreeentries: collapse two loops
[perl5.git] / hv.c
diff --git a/hv.c b/hv.c
index 44f385b..20c3531 100644 (file)
--- a/hv.c
+++ b/hv.c
@@ -1544,8 +1544,6 @@ Perl_hv_clear(pTHX_ HV *hv)
     else {
        hfreeentries(hv);
        HvPLACEHOLDERS_set(hv, 0);
     else {
        hfreeentries(hv);
        HvPLACEHOLDERS_set(hv, 0);
-       if (HvARRAY(hv))
-           Zero(HvARRAY(hv), xhv->xhv_max+1 /* HvMAX(hv)+1 */, HE*);
 
        if (SvRMAGICAL(hv))
            mg_clear(MUTABLE_SV(hv));
 
        if (SvRMAGICAL(hv))
            mg_clear(MUTABLE_SV(hv));
@@ -1633,6 +1631,7 @@ STATIC void
 S_hfreeentries(pTHX_ HV *hv)
 {
     int attempts = 100;
 S_hfreeentries(pTHX_ HV *hv)
 {
     int attempts = 100;
+    STRLEN i = 0;
     const bool mpm = PL_phase != PERL_PHASE_DESTRUCT && HvENAME(hv);
 
     PERL_ARGS_ASSERT_HFREEENTRIES;
     const bool mpm = PL_phase != PERL_PHASE_DESTRUCT && HvENAME(hv);
 
     PERL_ARGS_ASSERT_HFREEENTRIES;
@@ -1640,72 +1639,63 @@ S_hfreeentries(pTHX_ HV *hv)
     if (!HvARRAY(hv))
        return;
 
     if (!HvARRAY(hv))
        return;
 
-    /* we may need multiple attempts to empty the hash,
-     * since destructors may add things back. */
+    /* keep looping until all keys are removed. This may take multiple
+     * passes through the array, since destructors may add things back. */
 
 
-    while (1) {
+    while (((XPVHV*)SvANY(hv))->xhv_keys) {
        struct xpvhv_aux *iter;
        HE *entry;
        struct xpvhv_aux *iter;
        HE *entry;
-       STRLEN i = 0;
-
-       /* free all entries in all slots */
-       for (;;) {
-           HE ** const array = HvARRAY(hv);
-
-           if ( !((XPVHV*) SvANY(hv))->xhv_keys)
-               break;
-
-           if (SvOOK(hv) && ((iter = HvAUX(hv)))
-               && ((entry = iter->xhv_eiter)) )
-           {
-               /* the iterator may get resurrected after each
-                * destructor call, so check each time */
-               if (entry && HvLAZYDEL(hv)) {   /* was deleted earlier? */
-                   HvLAZYDEL_off(hv);
-                   hv_free_ent(hv, entry);
-               }
-               iter->xhv_riter = -1;   /* HvRITER(hv) = -1 */
-               iter->xhv_eiter = NULL; /* HvEITER(hv) = NULL */
-           }
-
-           entry = array[i];
-           if (entry) {
-               /* Detach this entry. Note that destructors may be
-                * called which will manipulate this hash, so make sure
-                * its internal structure remains consistent throughout */
-               array[i] = HeNEXT(entry);
-               ((XPVHV*) SvANY(hv))->xhv_keys--;
-
-               if (   mpm && HeVAL(entry) && isGV(HeVAL(entry))
-                   && GvHV(HeVAL(entry)) && HvENAME(GvHV(HeVAL(entry)))
-               ) {
-                   STRLEN klen;
-                   const char * const key = HePV(entry,klen);
-                   if ((klen > 1 && key[klen-1]==':' && key[klen-2]==':')
-                    || (klen == 1 && key[0] == ':')) {
-                       mro_package_moved(
-                        NULL, GvHV(HeVAL(entry)),
-                        (GV *)HeVAL(entry), 0
-                       );
-                   }
-               }
+       HE ** array;
+
+       if (SvOOK(hv) && ((iter = HvAUX(hv)))
+           && ((entry = iter->xhv_eiter)) )
+       {
+           /* the iterator may get resurrected after each
+            * destructor call, so check each time */
+           if (entry && HvLAZYDEL(hv)) {       /* was deleted earlier? */
+               HvLAZYDEL_off(hv);
                hv_free_ent(hv, entry);
                /* warning: at this point HvARRAY may have been
                 * re-allocated, HvMAX changed etc */
                hv_free_ent(hv, entry);
                /* warning: at this point HvARRAY may have been
                 * re-allocated, HvMAX changed etc */
-               continue;
            }
            }
-           if (i++ >= HvMAX(hv))
-               break;
+           iter->xhv_riter = -1;       /* HvRITER(hv) = -1 */
+           iter->xhv_eiter = NULL;     /* HvEITER(hv) = NULL */
        }
 
        }
 
-       if (((XPVHV*) SvANY(hv))->xhv_keys == 0)
-           /* Good. No-one added anything this time round.  */
-           break;
-
-       if (--attempts == 0) {
-           Perl_die(aTHX_ "panic: hfreeentries failed to free hash - something is repeatedly re-creating entries");
+       array = HvARRAY(hv);
+       entry = array[i];
+       if (entry) {
+           /* Detach and free this entry. Note that destructors may be
+            * called which will manipulate this hash, so make sure
+            * its internal structure remains consistent throughout */
+           array[i] = HeNEXT(entry);
+           ((XPVHV*) SvANY(hv))->xhv_keys--;
+
+           if (   mpm && HeVAL(entry) && isGV(HeVAL(entry))
+               && GvHV(HeVAL(entry)) && HvENAME(GvHV(HeVAL(entry)))
+           ) {
+               STRLEN klen;
+               const char * const key = HePV(entry,klen);
+               if ((klen > 1 && key[klen-1]==':' && key[klen-2]==':')
+                || (klen == 1 && key[0] == ':')) {
+                   mro_package_moved(
+                    NULL, GvHV(HeVAL(entry)),
+                    (GV *)HeVAL(entry), 0
+                   );
+               }
+           }
+           hv_free_ent(hv, entry);
+           /* warning: at this point HvARRAY may have been
+            * re-allocated, HvMAX changed etc */
+           continue;
        }
        }
-    }
+       if (i++ >= HvMAX(hv)) {
+           i = 0;
+           if (--attempts == 0) {
+               Perl_die(aTHX_ "panic: hfreeentries failed to free hash - something is repeatedly re-creating entries");
+           }
+       }
+    } /* while */
 }
 
 /*
 }
 
 /*
@@ -1745,17 +1735,10 @@ Perl_hv_undef_flags(pTHX_ HV *hv, U32 flags)
     if (SvOOK(hv)) {
       struct xpvhv_aux * const aux = HvAUX(hv);
       struct mro_meta *meta;
     if (SvOOK(hv)) {
       struct xpvhv_aux * const aux = HvAUX(hv);
       struct mro_meta *meta;
-      bool zeroed = FALSE;
 
       if ((name = HvENAME_get(hv))) {
 
       if ((name = HvENAME_get(hv))) {
-       if (PL_phase != PERL_PHASE_DESTRUCT) {
-           /* This must come at this point in case
-              mro_isa_changed_in dies. */
-           Zero(HvARRAY(hv), xhv->xhv_max+1 /* HvMAX(hv)+1 */, HE*);
-           zeroed = TRUE;
-
+       if (PL_phase != PERL_PHASE_DESTRUCT)
            mro_isa_changed_in(hv);
            mro_isa_changed_in(hv);
-       }
         if (PL_stashcache)
            (void)hv_delete(
                    PL_stashcache, name, HvENAMELEN_get(hv), G_DISCARD
         if (PL_stashcache)
            (void)hv_delete(
                    PL_stashcache, name, HvENAMELEN_get(hv), G_DISCARD
@@ -1789,8 +1772,6 @@ Perl_hv_undef_flags(pTHX_ HV *hv, U32 flags)
       }
       if (!aux->xhv_name_u.xhvnameu_name && ! aux->xhv_backreferences)
        SvFLAGS(hv) &= ~SVf_OOK;
       }
       if (!aux->xhv_name_u.xhvnameu_name && ! aux->xhv_backreferences)
        SvFLAGS(hv) &= ~SVf_OOK;
-      else if (!zeroed)
-       Zero(HvARRAY(hv), xhv->xhv_max+1 /* HvMAX(hv)+1 */, HE*);
     }
     if (!SvOOK(hv)) {
        Safefree(HvARRAY(hv));
     }
     if (!SvOOK(hv)) {
        Safefree(HvARRAY(hv));