This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
perlapi: Remove per-thread section; move to real scns
[perl5.git] / hv.c
diff --git a/hv.c b/hv.c
index e5bf629..32e1a7d 100644 (file)
--- a/hv.c
+++ b/hv.c
@@ -17,7 +17,7 @@
  */
 
 /* 
  */
 
 /* 
-=head1 Hash Manipulation Functions
+=head1 HV Handling
 A HV structure represents a Perl hash.  It consists mainly of an array
 of pointers, each of which points to a linked list of HE structures.  The
 array is indexed by the hash function of the key, so each linked list
 A HV structure represents a Perl hash.  It consists mainly of an array
 of pointers, each of which points to a linked list of HE structures.  The
 array is indexed by the hash function of the key, so each linked list
@@ -34,8 +34,11 @@ holds the key and hash value.
 #define PERL_HASH_INTERNAL_ACCESS
 #include "perl.h"
 
 #define PERL_HASH_INTERNAL_ACCESS
 #include "perl.h"
 
-#define DO_HSPLIT(xhv) ((xhv)->xhv_keys > (xhv)->xhv_max) /* HvTOTALKEYS(hv) > HvMAX(hv) */
-#define HV_FILL_THRESHOLD 31
+/* we split when we collide and we have a load factor over 0.667.
+ * NOTE if you change this formula so we split earlier than previously
+ * you MUST change the logic in hv_ksplit()
+ */
+#define DO_HSPLIT(xhv) ( ((xhv)->xhv_keys + ((xhv)->xhv_keys >> 1))  > (xhv)->xhv_max )
 
 static const char S_strtab_error[]
     = "Cannot modify shared string table in hv_%s";
 
 static const char S_strtab_error[]
     = "Cannot modify shared string table in hv_%s";
@@ -222,19 +225,19 @@ C<hash> parameter is the precomputed hash value; if it is zero then
 Perl will compute it.
 
 The return value will be
 Perl will compute it.
 
 The return value will be
-NULL if the operation failed or if the value did not need to be actually
+C<NULL> if the operation failed or if the value did not need to be actually
 stored within the hash (as in the case of tied hashes).  Otherwise it can
 be dereferenced to get the original C<SV*>.  Note that the caller is
 responsible for suitably incrementing the reference count of C<val> before
 stored within the hash (as in the case of tied hashes).  Otherwise it can
 be dereferenced to get the original C<SV*>.  Note that the caller is
 responsible for suitably incrementing the reference count of C<val> before
-the call, and decrementing it if the function returned NULL.  Effectively
-a successful hv_store takes ownership of one reference to C<val>.  This is
+the call, and decrementing it if the function returned C<NULL>.  Effectively
+a successful C<hv_store> takes ownership of one reference to C<val>.  This is
 usually what you want; a newly created SV has a reference count of one, so
 usually what you want; a newly created SV has a reference count of one, so
-if all your code does is create SVs then store them in a hash, hv_store
+if all your code does is create SVs then store them in a hash, C<hv_store>
 will own the only reference to the new SV, and your code doesn't need to do
 will own the only reference to the new SV, and your code doesn't need to do
-anything further to tidy up.  hv_store is not implemented as a call to
-hv_store_ent, and does not create a temporary SV for the key, so if your
-key data is not already in SV form then use hv_store in preference to
-hv_store_ent.
+anything further to tidy up.  C<hv_store> is not implemented as a call to
+C<hv_store_ent>, and does not create a temporary SV for the key, so if your
+key data is not already in SV form then use C<hv_store> in preference to
+C<hv_store_ent>.
 
 See L<perlguts/"Understanding the Magic of Tied Hashes and Arrays"> for more
 information on how to use this function on tied hashes.
 
 See L<perlguts/"Understanding the Magic of Tied Hashes and Arrays"> for more
 information on how to use this function on tied hashes.
@@ -244,22 +247,24 @@ information on how to use this function on tied hashes.
 Stores C<val> in a hash.  The hash key is specified as C<key>.  The C<hash>
 parameter is the precomputed hash value; if it is zero then Perl will
 compute it.  The return value is the new hash entry so created.  It will be
 Stores C<val> in a hash.  The hash key is specified as C<key>.  The C<hash>
 parameter is the precomputed hash value; if it is zero then Perl will
 compute it.  The return value is the new hash entry so created.  It will be
-NULL if the operation failed or if the value did not need to be actually
+C<NULL> if the operation failed or if the value did not need to be actually
 stored within the hash (as in the case of tied hashes).  Otherwise the
 contents of the return value can be accessed using the C<He?> macros
 described here.  Note that the caller is responsible for suitably
 incrementing the reference count of C<val> before the call, and
 decrementing it if the function returned NULL.  Effectively a successful
 stored within the hash (as in the case of tied hashes).  Otherwise the
 contents of the return value can be accessed using the C<He?> macros
 described here.  Note that the caller is responsible for suitably
 incrementing the reference count of C<val> before the call, and
 decrementing it if the function returned NULL.  Effectively a successful
-hv_store_ent takes ownership of one reference to C<val>.  This is
+C<hv_store_ent> takes ownership of one reference to C<val>.  This is
 usually what you want; a newly created SV has a reference count of one, so
 usually what you want; a newly created SV has a reference count of one, so
-if all your code does is create SVs then store them in a hash, hv_store
+if all your code does is create SVs then store them in a hash, C<hv_store>
 will own the only reference to the new SV, and your code doesn't need to do
 will own the only reference to the new SV, and your code doesn't need to do
-anything further to tidy up.  Note that hv_store_ent only reads the C<key>;
+anything further to tidy up.  Note that C<hv_store_ent> only reads the C<key>;
 unlike C<val> it does not take ownership of it, so maintaining the correct
 unlike C<val> it does not take ownership of it, so maintaining the correct
-reference count on C<key> is entirely the caller's responsibility.  hv_store
-is not implemented as a call to hv_store_ent, and does not create a temporary
+reference count on C<key> is entirely the caller's responsibility.  The reason
+it does not take ownership, is that C<key> is not used after this function
+returns, and so can be freed immediately.  C<hv_store>
+is not implemented as a call to C<hv_store_ent>, and does not create a temporary
 SV for the key, so if your key data is not already in SV form then use
 SV for the key, so if your key data is not already in SV form then use
-hv_store in preference to hv_store_ent.
+C<hv_store> in preference to C<hv_store_ent>.
 
 See L<perlguts/"Understanding the Magic of Tied Hashes and Arrays"> for more
 information on how to use this function on tied hashes.
 
 See L<perlguts/"Understanding the Magic of Tied Hashes and Arrays"> for more
 information on how to use this function on tied hashes.
@@ -337,12 +342,12 @@ void *
 Perl_hv_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
               int flags, int action, SV *val, U32 hash)
 {
 Perl_hv_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
               int flags, int action, SV *val, U32 hash)
 {
-    dVAR;
     XPVHV* xhv;
     HE *entry;
     HE **oentry;
     SV *sv;
     bool is_utf8;
     XPVHV* xhv;
     HE *entry;
     HE **oentry;
     SV *sv;
     bool is_utf8;
+    bool in_collision;
     int masked_flags;
     const int return_svp = action & HV_FETCH_JUST_SV;
     HEK *keysv_hek = NULL;
     int masked_flags;
     const int return_svp = action & HV_FETCH_JUST_SV;
     HEK *keysv_hek = NULL;
@@ -387,15 +392,16 @@ Perl_hv_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
        if (SvIsCOW_shared_hash(keysv)) {
            flags = HVhek_KEYCANONICAL | (is_utf8 ? HVhek_UTF8 : 0);
        } else {
        if (SvIsCOW_shared_hash(keysv)) {
            flags = HVhek_KEYCANONICAL | (is_utf8 ? HVhek_UTF8 : 0);
        } else {
-           flags = is_utf8 ? HVhek_UTF8 : 0;
+           flags = 0;
        }
     } else {
        }
     } else {
-       is_utf8 = ((flags & HVhek_UTF8) ? TRUE : FALSE);
+       is_utf8 = cBOOL(flags & HVhek_UTF8);
     }
 
     if (action & HV_DELETE) {
        return (void *) hv_delete_common(hv, keysv, key, klen,
     }
 
     if (action & HV_DELETE) {
        return (void *) hv_delete_common(hv, keysv, key, klen,
-                                        flags, action, hash);
+                                        flags | (is_utf8 ? HVhek_UTF8 : 0),
+                                        action, hash);
     }
 
     xhv = (XPVHV*)SvANY(hv);
     }
 
     xhv = (XPVHV*)SvANY(hv);
@@ -496,11 +502,15 @@ Perl_hv_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
                }
                if (flags & HVhek_FREEKEY)
                    Safefree(key);
                }
                if (flags & HVhek_FREEKEY)
                    Safefree(key);
-               magic_existspack(svret, mg_find(sv, PERL_MAGIC_tiedelem));
+               {
+                  MAGIC * const mg = mg_find(sv, PERL_MAGIC_tiedelem);
+                  if (mg)
+                    magic_existspack(svret, mg);
+               }
                /* This cast somewhat evil, but I'm merely using NULL/
                   not NULL to return the boolean exists.
                   And I know hv is not NULL.  */
                /* This cast somewhat evil, but I'm merely using NULL/
                   not NULL to return the boolean exists.
                   And I know hv is not NULL.  */
-               return SvTRUE(svret) ? (void *)hv : NULL;
+               return SvTRUE_NN(svret) ? (void *)hv : NULL;
                }
 #ifdef ENV_IS_CASELESS
            else if (mg_find((const SV *)hv, PERL_MAGIC_env)) {
                }
 #ifdef ENV_IS_CASELESS
            else if (mg_find((const SV *)hv, PERL_MAGIC_env)) {
@@ -738,7 +748,7 @@ Perl_hv_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
        if (flags & HVhek_FREEKEY)
            Safefree(key);
        if (return_svp) {
        if (flags & HVhek_FREEKEY)
            Safefree(key);
        if (return_svp) {
-           return entry ? (void *) &HeVAL(entry) : NULL;
+            return (void *) &HeVAL(entry);
        }
        return entry;
     }
        }
        return entry;
     }
@@ -762,7 +772,7 @@ Perl_hv_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
 
     if (!entry && SvREADONLY(hv) && !(action & HV_FETCH_ISEXISTS)) {
        hv_notallowed(flags, key, klen,
 
     if (!entry && SvREADONLY(hv) && !(action & HV_FETCH_ISEXISTS)) {
        hv_notallowed(flags, key, klen,
-                       "Attempt to access disallowed key '%"SVf"' in"
+                       "Attempt to access disallowed key '%" SVf "' in"
                        " a restricted hash");
     }
     if (!(action & (HV_FETCH_LVALUE|HV_FETCH_ISSTORE))) {
                        " a restricted hash");
     }
     if (!(action & (HV_FETCH_LVALUE|HV_FETCH_ISSTORE))) {
@@ -825,19 +835,13 @@ Perl_hv_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
        HeKEY_hek(entry) = save_hek_flags(key, klen, hash, flags);
     HeVAL(entry) = val;
 
        HeKEY_hek(entry) = save_hek_flags(key, klen, hash, flags);
     HeVAL(entry) = val;
 
-    if (!*oentry && SvOOK(hv)) {
-        /* initial entry, and aux struct present.  */
-        struct xpvhv_aux *const aux = HvAUX(hv);
-        if (aux->xhv_fill_lazy)
-            ++aux->xhv_fill_lazy;
-    }
-
 #ifdef PERL_HASH_RANDOMIZE_KEYS
     /* This logic semi-randomizes the insert order in a bucket.
      * Either we insert into the top, or the slot below the top,
      * making it harder to see if there is a collision. We also
      * reset the iterator randomizer if there is one.
      */
 #ifdef PERL_HASH_RANDOMIZE_KEYS
     /* This logic semi-randomizes the insert order in a bucket.
      * Either we insert into the top, or the slot below the top,
      * making it harder to see if there is a collision. We also
      * reset the iterator randomizer if there is one.
      */
+    in_collision = *oentry != NULL;
     if ( *oentry && PL_HASH_RAND_BITS_ENABLED) {
         PL_hash_rand_bits++;
         PL_hash_rand_bits= ROTL_UV(PL_hash_rand_bits,1);
     if ( *oentry && PL_HASH_RAND_BITS_ENABLED) {
         PL_hash_rand_bits++;
         PL_hash_rand_bits= ROTL_UV(PL_hash_rand_bits,1);
@@ -880,7 +884,7 @@ Perl_hv_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
        HvHASKFLAGS_on(hv);
 
     xhv->xhv_keys++; /* HvTOTALKEYS(hv)++ */
        HvHASKFLAGS_on(hv);
 
     xhv->xhv_keys++; /* HvTOTALKEYS(hv)++ */
-    if ( DO_HSPLIT(xhv) ) {
+    if ( in_collision && DO_HSPLIT(xhv) ) {
         const STRLEN oldsize = xhv->xhv_max + 1;
         const U32 items = (U32)HvPLACEHOLDERS_get(hv);
 
         const STRLEN oldsize = xhv->xhv_max + 1;
         const U32 items = (U32)HvPLACEHOLDERS_get(hv);
 
@@ -933,8 +937,14 @@ S_hv_magic_check(HV *hv, bool *needs_copy, bool *needs_store)
 /*
 =for apidoc hv_scalar
 
 /*
 =for apidoc hv_scalar
 
-Evaluates the hash in scalar context and returns the result.  Handles magic
-when the hash is tied.
+Evaluates the hash in scalar context and returns the result.
+
+When the hash is tied dispatches through to the SCALAR method,
+otherwise returns a mortal SV containing the number of keys
+in the hash.
+
+Note, prior to 5.25 this function returned what is now
+returned by the hv_bucket_ratio() function.
 
 =cut
 */
 
 =cut
 */
@@ -953,11 +963,119 @@ Perl_hv_scalar(pTHX_ HV *hv)
     }
 
     sv = sv_newmortal();
     }
 
     sv = sv_newmortal();
-    if (HvTOTALKEYS((const HV *)hv)) 
+    sv_setuv(sv, HvUSEDKEYS(hv));
+
+    return sv;
+}
+
+
+/*
+hv_pushkv(): push all the keys and/or values of a hash onto the stack.
+The rough Perl equivalents:
+    () = %hash;
+    () = keys %hash;
+    () = values %hash;
+
+Resets the hash's iterator.
+
+flags : 1   = push keys
+        2   = push values
+        1|2 = push keys and values
+        XXX use symbolic flag constants at some point?
+I might unroll the non-tied hv_iternext() in here at some point - DAPM
+*/
+
+void
+Perl_hv_pushkv(pTHX_ HV *hv, U32 flags)
+{
+    HE *entry;
+    bool tied = SvRMAGICAL(hv) && (mg_find(MUTABLE_SV(hv), PERL_MAGIC_tied)
+#ifdef DYNAMIC_ENV_FETCH  /* might not know number of keys yet */
+                                   || mg_find(MUTABLE_SV(hv), PERL_MAGIC_env)
+#endif
+                                  );
+    dSP;
+
+    PERL_ARGS_ASSERT_HV_PUSHKV;
+    assert(flags); /* must be pushing at least one of keys and values */
+
+    (void)hv_iterinit(hv);
+
+    if (tied) {
+        SSize_t ext = (flags == 3) ? 2 : 1;
+        while ((entry = hv_iternext(hv))) {
+            EXTEND(SP, ext);
+            if (flags & 1)
+                PUSHs(hv_iterkeysv(entry));
+            if (flags & 2)
+                PUSHs(hv_iterval(hv, entry));
+        }
+    }
+    else {
+        Size_t nkeys = HvUSEDKEYS(hv);
+        SSize_t ext;
+
+        if (!nkeys)
+            return;
+
+        /* 2*nkeys() should never be big enough to truncate or wrap */
+        assert(nkeys <= (SSize_t_MAX >> 1));
+        ext = nkeys * ((flags == 3) ? 2 : 1);
+
+        EXTEND_MORTAL(nkeys);
+        EXTEND(SP, ext);
+
+        while ((entry = hv_iternext(hv))) {
+            if (flags & 1) {
+                SV *keysv = newSVhek(HeKEY_hek(entry));
+                SvTEMP_on(keysv);
+                PL_tmps_stack[++PL_tmps_ix] = keysv;
+                PUSHs(keysv);
+            }
+            if (flags & 2)
+                PUSHs(HeVAL(entry));
+        }
+    }
+
+    PUTBACK;
+}
+
+
+/*
+=for apidoc hv_bucket_ratio
+
+If the hash is tied dispatches through to the SCALAR tied method,
+otherwise if the hash contains no keys returns 0, otherwise returns
+a mortal sv containing a string specifying the number of used buckets,
+followed by a slash, followed by the number of available buckets.
+
+This function is expensive, it must scan all of the buckets
+to determine which are used, and the count is NOT cached.
+In a large hash this could be a lot of buckets.
+
+=cut
+*/
+
+SV *
+Perl_hv_bucket_ratio(pTHX_ HV *hv)
+{
+    SV *sv;
+
+    PERL_ARGS_ASSERT_HV_BUCKET_RATIO;
+
+    if (SvRMAGICAL(hv)) {
+        MAGIC * const mg = mg_find((const SV *)hv, PERL_MAGIC_tied);
+        if (mg)
+            return magic_scalarpack(hv, mg);
+    }
+
+    if (HvUSEDKEYS((HV *)hv)) {
+        sv = sv_newmortal();
         Perl_sv_setpvf(aTHX_ sv, "%ld/%ld",
                 (long)HvFILL(hv), (long)HvMAX(hv) + 1);
         Perl_sv_setpvf(aTHX_ sv, "%ld/%ld",
                 (long)HvFILL(hv), (long)HvMAX(hv) + 1);
+    }
     else
     else
-        sv_setiv(sv, 0);
+        sv = &PL_sv_zero;
     
     return sv;
 }
     
     return sv;
 }
@@ -969,15 +1087,15 @@ Deletes a key/value pair in the hash.  The value's SV is removed from
 the hash, made mortal, and returned to the caller.  The absolute
 value of C<klen> is the length of the key.  If C<klen> is negative the
 key is assumed to be in UTF-8-encoded Unicode.  The C<flags> value
 the hash, made mortal, and returned to the caller.  The absolute
 value of C<klen> is the length of the key.  If C<klen> is negative the
 key is assumed to be in UTF-8-encoded Unicode.  The C<flags> value
-will normally be zero; if set to G_DISCARD then NULL will be returned.
-NULL will also be returned if the key is not found.
+will normally be zero; if set to C<G_DISCARD> then C<NULL> will be returned.
+C<NULL> will also be returned if the key is not found.
 
 =for apidoc hv_delete_ent
 
 Deletes a key/value pair in the hash.  The value SV is removed from the hash,
 made mortal, and returned to the caller.  The C<flags> value will normally be
 
 =for apidoc hv_delete_ent
 
 Deletes a key/value pair in the hash.  The value SV is removed from the hash,
 made mortal, and returned to the caller.  The C<flags> value will normally be
-zero; if set to G_DISCARD then NULL will be returned.  NULL will also be
-returned if the key is not found.  C<hash> can be a valid precomputed hash
+zero; if set to C<G_DISCARD> then C<NULL> will be returned.  C<NULL> will also
+be returned if the key is not found.  C<hash> can be a valid precomputed hash
 value, or 0 to ask for it to be computed.
 
 =cut
 value, or 0 to ask for it to be computed.
 
 =cut
@@ -987,12 +1105,11 @@ STATIC SV *
 S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
                   int k_flags, I32 d_flags, U32 hash)
 {
 S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
                   int k_flags, I32 d_flags, U32 hash)
 {
-    dVAR;
     XPVHV* xhv;
     HE *entry;
     HE **oentry;
     HE **first_entry;
     XPVHV* xhv;
     HE *entry;
     HE **oentry;
     HE **first_entry;
-    bool is_utf8 = (k_flags & HVhek_UTF8) ? TRUE : FALSE;
+    bool is_utf8 = cBOOL(k_flags & HVhek_UTF8);
     int masked_flags;
     HEK *keysv_hek = NULL;
     U8 mro_changes = 0; /* 1 = isa; 2 = package moved */
     int masked_flags;
     HEK *keysv_hek = NULL;
     U8 mro_changes = 0; /* 1 = isa; 2 = package moved */
@@ -1131,7 +1248,7 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
        }
        if (SvREADONLY(hv) && HeVAL(entry) && SvREADONLY(HeVAL(entry))) {
            hv_notallowed(k_flags, key, klen,
        }
        if (SvREADONLY(hv) && HeVAL(entry) && SvREADONLY(HeVAL(entry))) {
            hv_notallowed(k_flags, key, klen,
-                           "Attempt to delete readonly key '%"SVf"' from"
+                           "Attempt to delete readonly key '%" SVf "' from"
                            " a restricted hash");
        }
         if (k_flags & HVhek_FREEKEY)
                            " a restricted hash");
        }
         if (k_flags & HVhek_FREEKEY)
@@ -1162,8 +1279,73 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
                         sv_2mortal((SV *)gv)
                        );
                }
                         sv_2mortal((SV *)gv)
                        );
                }
-               else if (klen == 3 && strnEQ(key, "ISA", 3))
+               else if (memEQs(key, klen, "ISA") && GvAV(gv)) {
+                    AV *isa = GvAV(gv);
+                    MAGIC *mg = mg_find((SV*)isa, PERL_MAGIC_isa);
+
                    mro_changes = 1;
                    mro_changes = 1;
+                    if (mg) {
+                        if (mg->mg_obj == (SV*)gv) {
+                            /* This is the only stash this ISA was used for.
+                             * The isaelem magic asserts if there's no
+                             * isa magic on the array, so explicitly
+                             * remove the magic on both the array and its
+                             * elements.  @ISA shouldn't be /too/ large.
+                             */
+                            SV **svp, **end;
+                        strip_magic:
+                            svp = AvARRAY(isa);
+                            end = svp + (AvFILLp(isa)+1);
+                            while (svp < end) {
+                                if (*svp)
+                                    mg_free_type(*svp, PERL_MAGIC_isaelem);
+                                ++svp;
+                            }
+                            mg_free_type((SV*)GvAV(gv), PERL_MAGIC_isa);
+                        }
+                        else {
+                            /* mg_obj is an array of stashes
+                               Note that the array doesn't keep a reference
+                               count on the stashes.
+                             */
+                            AV *av = (AV*)mg->mg_obj;
+                            SV **svp, **arrayp;
+                            SSize_t index;
+                            SSize_t items;
+
+                            assert(SvTYPE(mg->mg_obj) == SVt_PVAV);
+
+                            /* remove the stash from the magic array */
+                            arrayp = svp = AvARRAY(av);
+                            items = AvFILLp(av) + 1;
+                            if (items == 1) {
+                                assert(*arrayp == (SV *)gv);
+                                mg->mg_obj = NULL;
+                                /* avoid a double free on the last stash */
+                                AvFILLp(av) = -1;
+                                /* The magic isn't MGf_REFCOUNTED, so release
+                                 * the array manually.
+                                 */
+                                SvREFCNT_dec_NN(av);
+                                goto strip_magic;
+                            }
+                            else {
+                                while (items--) {
+                                    if (*svp == (SV*)gv)
+                                        break;
+                                    ++svp;
+                                }
+                                index = svp - arrayp;
+                                assert(index >= 0 && index <= AvFILLp(av));
+                                if (index < AvFILLp(av)) {
+                                    arrayp[index] = arrayp[AvFILLp(av)];
+                                }
+                                arrayp[AvFILLp(av)] = NULL;
+                                --AvFILLp(av);
+                            }
+                        }
+                    }
+                }
        }
 
        sv = d_flags & G_DISCARD ? HeVAL(entry) : sv_2mortal(HeVAL(entry));
        }
 
        sv = d_flags & G_DISCARD ? HeVAL(entry) : sv_2mortal(HeVAL(entry));
@@ -1187,12 +1369,6 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
            HvPLACEHOLDERS(hv)++;
        else {
            *oentry = HeNEXT(entry);
            HvPLACEHOLDERS(hv)++;
        else {
            *oentry = HeNEXT(entry);
-            if(!*first_entry && SvOOK(hv)) {
-                /* removed last entry, and aux struct present.  */
-                struct xpvhv_aux *const aux = HvAUX(hv);
-                if (aux->xhv_fill_lazy)
-                    --aux->xhv_fill_lazy;
-            }
            if (SvOOK(hv) && entry == HvAUX(hv)->xhv_eiter /* HvEITER(hv) */)
                HvLAZYDEL_on(hv);
            else {
            if (SvOOK(hv) && entry == HvAUX(hv)->xhv_eiter /* HvEITER(hv) */)
                HvLAZYDEL_on(hv);
            else {
@@ -1221,7 +1397,7 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
   not_found:
     if (SvREADONLY(hv)) {
        hv_notallowed(k_flags, key, klen,
   not_found:
     if (SvREADONLY(hv)) {
        hv_notallowed(k_flags, key, klen,
-                       "Attempt to delete disallowed key '%"SVf"' from"
+                       "Attempt to delete disallowed key '%" SVf "' from"
                        " a restricted hash");
     }
 
                        " a restricted hash");
     }
 
@@ -1284,10 +1460,6 @@ S_hsplit(pTHX_ HV *hv, STRLEN const oldsize, STRLEN newsize)
 #ifdef PERL_HASH_RANDOMIZE_KEYS
             dest->xhv_rand = (U32)PL_hash_rand_bits;
 #endif
 #ifdef PERL_HASH_RANDOMIZE_KEYS
             dest->xhv_rand = (U32)PL_hash_rand_bits;
 #endif
-            /* For now, just reset the lazy fill counter.
-               It would be possible to update the counter in the code below
-               instead.  */
-            dest->xhv_fill_lazy = 0;
         } else {
             /* no existing aux structure, but we allocated space for one
              * so initialize it properly. This unrolls hv_auxinit() a bit,
         } else {
             /* no existing aux structure, but we allocated space for one
              * so initialize it properly. This unrolls hv_auxinit() a bit,
@@ -1358,29 +1530,42 @@ void
 Perl_hv_ksplit(pTHX_ HV *hv, IV newmax)
 {
     XPVHV* xhv = (XPVHV*)SvANY(hv);
 Perl_hv_ksplit(pTHX_ HV *hv, IV newmax)
 {
     XPVHV* xhv = (XPVHV*)SvANY(hv);
-    const I32 oldsize = (I32) xhv->xhv_max+1; /* HvMAX(hv)+1 (sick) */
+    const I32 oldsize = (I32) xhv->xhv_max+1;       /* HvMAX(hv)+1 */
     I32 newsize;
     I32 newsize;
+    I32 wantsize;
+    I32 trysize;
     char *a;
 
     PERL_ARGS_ASSERT_HV_KSPLIT;
 
     char *a;
 
     PERL_ARGS_ASSERT_HV_KSPLIT;
 
-    newsize = (I32) newmax;                    /* possible truncation here */
-    if (newsize != newmax || newmax <= oldsize)
+    wantsize = (I32) newmax;                            /* possible truncation here */
+    if (wantsize != newmax)
        return;
        return;
-    while ((newsize & (1 + ~newsize)) != newsize) {
-       newsize &= ~(newsize & (1 + ~newsize)); /* get proper power of 2 */
+
+    wantsize= wantsize + (wantsize >> 1);           /* wantsize *= 1.5 */
+    if (wantsize < newmax)                          /* overflow detection */
+        return;
+
+    newsize = oldsize;
+    while (wantsize > newsize) {
+        trysize = newsize << 1;
+        if (trysize > newsize) {
+            newsize = trysize;
+        } else {
+            /* we overflowed */
+            return;
+        }
     }
     }
-    if (newsize < newmax)
-       newsize *= 2;
-    if (newsize < newmax)
-       return;                                 /* overflow detection */
+
+    if (newsize <= oldsize)
+        return;                                            /* overflow detection */
 
     a = (char *) HvARRAY(hv);
     if (a) {
         hsplit(hv, oldsize, newsize);
     } else {
         Newxz(a, PERL_HV_ARRAY_ALLOC_BYTES(newsize), char);
 
     a = (char *) HvARRAY(hv);
     if (a) {
         hsplit(hv, oldsize, newsize);
     } else {
         Newxz(a, PERL_HV_ARRAY_ALLOC_BYTES(newsize), char);
-        xhv->xhv_max = --newsize;
+        xhv->xhv_max = newsize - 1;
         HvARRAY(hv) = (HE **) a;
     }
 }
         HvARRAY(hv) = (HE **) a;
     }
 }
@@ -1403,7 +1588,6 @@ Perl_hv_ksplit(pTHX_ HV *hv, IV newmax)
 HV *
 Perl_newHVhv(pTHX_ HV *ohv)
 {
 HV *
 Perl_newHVhv(pTHX_ HV *ohv)
 {
-    dVAR;
     HV * const hv = newHV();
     STRLEN hv_max;
 
     HV * const hv = newHV();
     STRLEN hv_max;
 
@@ -1484,12 +1668,12 @@ Perl_newHVhv(pTHX_ HV *ohv)
 }
 
 /*
 }
 
 /*
-=for apidoc Am|HV *|hv_copy_hints_hv|HV *ohv
+=for apidoc hv_copy_hints_hv
 
 
-A specialised version of L</newHVhv> for copying C<%^H>.  I<ohv> must be
+A specialised version of L</newHVhv> for copying C<%^H>.  C<ohv> must be
 a pointer to a hash (which may have C<%^H> magic, but should be generally
 non-magical), or C<NULL> (interpreted as an empty hash).  The content
 a pointer to a hash (which may have C<%^H> magic, but should be generally
 non-magical), or C<NULL> (interpreted as an empty hash).  The content
-of I<ohv> is copied to a new hash, which has the C<%^H>-specific magic
+of C<ohv> is copied to a new hash, which has the C<%^H>-specific magic
 added to it.  A pointer to the new hash is returned.
 
 =cut
 added to it.  A pointer to the new hash is returned.
 
 =cut
@@ -1592,11 +1776,11 @@ Perl_hv_delayfree_ent(pTHX_ HV *hv, HE *entry)
 /*
 =for apidoc hv_clear
 
 /*
 =for apidoc hv_clear
 
-Frees the all the elements of a hash, leaving it empty.
+Frees all the elements of a hash, leaving it empty.
 The XS equivalent of C<%hash = ()>.  See also L</hv_undef>.
 
 The XS equivalent of C<%hash = ()>.  See also L</hv_undef>.
 
-If any destructors are triggered as a result, the hv itself may
-be freed.
+See L</av_clear> for a note about the hash possibly being invalid on
+return.
 
 =cut
 */
 
 =cut
 */
@@ -1604,7 +1788,8 @@ be freed.
 void
 Perl_hv_clear(pTHX_ HV *hv)
 {
 void
 Perl_hv_clear(pTHX_ HV *hv)
 {
-    dVAR;
+    SSize_t orig_ix;
+
     XPVHV* xhv;
     if (!hv)
        return;
     XPVHV* xhv;
     if (!hv)
        return;
@@ -1613,8 +1798,10 @@ Perl_hv_clear(pTHX_ HV *hv)
 
     xhv = (XPVHV*)SvANY(hv);
 
 
     xhv = (XPVHV*)SvANY(hv);
 
-    ENTER;
-    SAVEFREESV(SvREFCNT_inc_simple_NN(hv));
+    /* avoid hv being freed when calling destructors below */
+    EXTEND_MORTAL(1);
+    PL_tmps_stack[++PL_tmps_ix] = SvREFCNT_inc_simple_NN(hv);
+    orig_ix = PL_tmps_ix;
     if (SvREADONLY(hv) && HvARRAY(hv) != NULL) {
        /* restricted hash: convert all keys to placeholders */
        STRLEN i;
     if (SvREADONLY(hv) && HvARRAY(hv) != NULL) {
        /* restricted hash: convert all keys to placeholders */
        STRLEN i;
@@ -1627,7 +1814,7 @@ Perl_hv_clear(pTHX_ HV *hv)
                        if (SvREADONLY(HeVAL(entry))) {
                            SV* const keysv = hv_iterkeysv(entry);
                            Perl_croak_nocontext(
                        if (SvREADONLY(HeVAL(entry))) {
                            SV* const keysv = hv_iterkeysv(entry);
                            Perl_croak_nocontext(
-                               "Attempt to delete readonly key '%"SVf"' from a restricted hash",
+                               "Attempt to delete readonly key '%" SVf "' from a restricted hash",
                                (void*)keysv);
                        }
                        SvREFCNT_dec_NN(HeVAL(entry));
                                (void*)keysv);
                        }
                        SvREFCNT_dec_NN(HeVAL(entry));
@@ -1639,7 +1826,7 @@ Perl_hv_clear(pTHX_ HV *hv)
        }
     }
     else {
        }
     }
     else {
-       hfreeentries(hv);
+       hv_free_entries(hv);
        HvPLACEHOLDERS_set(hv, 0);
 
        if (SvRMAGICAL(hv))
        HvPLACEHOLDERS_set(hv, 0);
 
        if (SvRMAGICAL(hv))
@@ -1652,7 +1839,12 @@ Perl_hv_clear(pTHX_ HV *hv)
             mro_isa_changed_in(hv);
        HvEITER_set(hv, NULL);
     }
             mro_isa_changed_in(hv);
        HvEITER_set(hv, NULL);
     }
-    LEAVE;
+    /* disarm hv's premature free guard */
+    if (LIKELY(PL_tmps_ix == orig_ix))
+        PL_tmps_ix--;
+    else
+        PL_tmps_stack[orig_ix] = &PL_sv_undef;
+    SvREFCNT_dec_NN(hv);
 }
 
 /*
 }
 
 /*
@@ -1660,11 +1852,12 @@ Perl_hv_clear(pTHX_ HV *hv)
 
 Clears any placeholders from a hash.  If a restricted hash has any of its keys
 marked as readonly and the key is subsequently deleted, the key is not actually
 
 Clears any placeholders from a hash.  If a restricted hash has any of its keys
 marked as readonly and the key is subsequently deleted, the key is not actually
-deleted but is marked by assigning it a value of &PL_sv_placeholder.  This tags
+deleted but is marked by assigning it a value of C<&PL_sv_placeholder>.  This tags
 it so it will be ignored by future operations such as iterating over the hash,
 but will still allow the hash to have a value reassigned to the key at some
 future point.  This function clears any such placeholder keys from the hash.
 it so it will be ignored by future operations such as iterating over the hash,
 but will still allow the hash to have a value reassigned to the key at some
 future point.  This function clears any such placeholder keys from the hash.
-See Hash::Util::lock_keys() for an example of its use.
+See C<L<Hash::Util::lock_keys()|Hash::Util/lock_keys>> for an example of its
+use.
 
 =cut
 */
 
 =cut
 */
@@ -1683,7 +1876,6 @@ Perl_hv_clear_placeholders(pTHX_ HV *hv)
 static void
 S_clear_placeholders(pTHX_ HV *hv, U32 items)
 {
 static void
 S_clear_placeholders(pTHX_ HV *hv, U32 items)
 {
-    dVAR;
     I32 i;
 
     PERL_ARGS_ASSERT_CLEAR_PLACEHOLDERS;
     I32 i;
 
     PERL_ARGS_ASSERT_CLEAR_PLACEHOLDERS;
@@ -1730,13 +1922,13 @@ S_clear_placeholders(pTHX_ HV *hv, U32 items)
 }
 
 STATIC void
 }
 
 STATIC void
-S_hfreeentries(pTHX_ HV *hv)
+S_hv_free_entries(pTHX_ HV *hv)
 {
     STRLEN index = 0;
     XPVHV * const xhv = (XPVHV*)SvANY(hv);
     SV *sv;
 
 {
     STRLEN index = 0;
     XPVHV * const xhv = (XPVHV*)SvANY(hv);
     SV *sv;
 
-    PERL_ARGS_ASSERT_HFREEENTRIES;
+    PERL_ARGS_ASSERT_HV_FREE_ENTRIES;
 
     while ((sv = Perl_hfree_next_entry(aTHX_ hv, &index))||xhv->xhv_keys) {
        SvREFCNT_dec(sv);
 
     while ((sv = Perl_hfree_next_entry(aTHX_ hv, &index))||xhv->xhv_keys) {
        SvREFCNT_dec(sv);
@@ -1745,7 +1937,7 @@ S_hfreeentries(pTHX_ HV *hv)
 
 
 /* hfree_next_entry()
 
 
 /* hfree_next_entry()
- * For use only by S_hfreeentries() and sv_clear().
+ * For use only by S_hv_free_entries() and sv_clear().
  * Delete the next available HE from hv and return the associated SV.
  * Returns null on empty hash. Nevertheless null is not a reliable
  * indicator that the hash is empty, as the deleted entry may have a
  * Delete the next available HE from hv and return the associated SV.
  * Returns null on empty hash. Nevertheless null is not a reliable
  * indicator that the hash is empty, as the deleted entry may have a
@@ -1782,12 +1974,6 @@ Perl_hfree_next_entry(pTHX_ HV *hv, STRLEN *indexp)
             iter->xhv_last_rand = iter->xhv_rand;
 #endif
         }
             iter->xhv_last_rand = iter->xhv_rand;
 #endif
         }
-        /* Reset any cached HvFILL() to "unknown".  It's unlikely that anyone
-           will actually call HvFILL() on a hash under destruction, so it
-           seems pointless attempting to track the number of keys remaining.
-           But if they do, we want to reset it again.  */
-        if (iter->xhv_fill_lazy)
-            iter->xhv_fill_lazy = 0;
     }
 
     if (!((XPVHV*)SvANY(hv))->xhv_keys)
     }
 
     if (!((XPVHV*)SvANY(hv))->xhv_keys)
@@ -1826,13 +2012,11 @@ Perl_hfree_next_entry(pTHX_ HV *hv, STRLEN *indexp)
 
 Undefines the hash.  The XS equivalent of C<undef(%hash)>.
 
 
 Undefines the hash.  The XS equivalent of C<undef(%hash)>.
 
-As well as freeing all the elements of the hash (like hv_clear()), this
+As well as freeing all the elements of the hash (like C<hv_clear()>), this
 also frees any auxiliary data and storage associated with the hash.
 
 also frees any auxiliary data and storage associated with the hash.
 
-If any destructors are triggered as a result, the hv itself may
-be freed.
-
-See also L</hv_clear>.
+See L</av_clear> for a note about the hash possibly being invalid on
+return.
 
 =cut
 */
 
 =cut
 */
@@ -1842,14 +2026,15 @@ Perl_hv_undef_flags(pTHX_ HV *hv, U32 flags)
 {
     XPVHV* xhv;
     bool save;
 {
     XPVHV* xhv;
     bool save;
+    SSize_t orig_ix = PL_tmps_ix; /* silence compiler warning about unitialized vars */
 
     if (!hv)
        return;
 
     if (!hv)
        return;
-    save = !!SvREFCNT(hv);
+    save = cBOOL(SvREFCNT(hv));
     DEBUG_A(Perl_hv_assert(aTHX_ hv));
     xhv = (XPVHV*)SvANY(hv);
 
     DEBUG_A(Perl_hv_assert(aTHX_ hv));
     xhv = (XPVHV*)SvANY(hv);
 
-    /* The name must be deleted before the call to hfreeeeentries so that
+    /* The name must be deleted before the call to hv_free_entries so that
        CVs are anonymised properly. But the effective name must be pre-
        served until after that call (and only deleted afterwards if the
        call originated from sv_clear). For stashes with one name that is
        CVs are anonymised properly. But the effective name must be pre-
        served until after that call (and only deleted afterwards if the
        call originated from sv_clear). For stashes with one name that is
@@ -1857,21 +2042,23 @@ Perl_hv_undef_flags(pTHX_ HV *hv, U32 flags)
        allocate an array for storing the effective name. We can skip that
        during global destruction, as it does not matter where the CVs point
        if they will be freed anyway. */
        allocate an array for storing the effective name. We can skip that
        during global destruction, as it does not matter where the CVs point
        if they will be freed anyway. */
-    /* note that the code following prior to hfreeentries is duplicated
+    /* note that the code following prior to hv_free_entries is duplicated
      * in sv_clear(), and changes here should be done there too */
     if (PL_phase != PERL_PHASE_DESTRUCT && HvNAME(hv)) {
         if (PL_stashcache) {
             DEBUG_o(Perl_deb(aTHX_ "hv_undef_flags clearing PL_stashcache for '%"
      * in sv_clear(), and changes here should be done there too */
     if (PL_phase != PERL_PHASE_DESTRUCT && HvNAME(hv)) {
         if (PL_stashcache) {
             DEBUG_o(Perl_deb(aTHX_ "hv_undef_flags clearing PL_stashcache for '%"
-                             HEKf"'\n", HEKfARG(HvNAME_HEK(hv))));
+                             HEKf "'\n", HEKfARG(HvNAME_HEK(hv))));
            (void)hv_deletehek(PL_stashcache, HvNAME_HEK(hv), G_DISCARD);
         }
        hv_name_set(hv, NULL, 0, 0);
     }
     if (save) {
            (void)hv_deletehek(PL_stashcache, HvNAME_HEK(hv), G_DISCARD);
         }
        hv_name_set(hv, NULL, 0, 0);
     }
     if (save) {
-       ENTER;
-       SAVEFREESV(SvREFCNT_inc_simple_NN(hv));
+        /* avoid hv being freed when calling destructors below */
+        EXTEND_MORTAL(1);
+        PL_tmps_stack[++PL_tmps_ix] = SvREFCNT_inc_simple_NN(hv);
+        orig_ix = PL_tmps_ix;
     }
     }
-    hfreeentries(hv);
+    hv_free_entries(hv);
     if (SvOOK(hv)) {
       struct mro_meta *meta;
       const char *name;
     if (SvOOK(hv)) {
       struct mro_meta *meta;
       const char *name;
@@ -1881,7 +2068,7 @@ Perl_hv_undef_flags(pTHX_ HV *hv, U32 flags)
            mro_isa_changed_in(hv);
         if (PL_stashcache) {
             DEBUG_o(Perl_deb(aTHX_ "hv_undef_flags clearing PL_stashcache for effective name '%"
            mro_isa_changed_in(hv);
         if (PL_stashcache) {
             DEBUG_o(Perl_deb(aTHX_ "hv_undef_flags clearing PL_stashcache for effective name '%"
-                             HEKf"'\n", HEKfARG(HvENAME_HEK(hv))));
+                             HEKf "'\n", HEKfARG(HvENAME_HEK(hv))));
            (void)hv_deletehek(PL_stashcache, HvENAME_HEK(hv), G_DISCARD);
         }
       }
            (void)hv_deletehek(PL_stashcache, HvENAME_HEK(hv), G_DISCARD);
         }
       }
@@ -1892,7 +2079,7 @@ Perl_hv_undef_flags(pTHX_ HV *hv, U32 flags)
       if (flags & HV_NAME_SETALL ? !!HvAUX(hv)->xhv_name_u.xhvnameu_name : !!name) {
         if (name && PL_stashcache) {
             DEBUG_o(Perl_deb(aTHX_ "hv_undef_flags clearing PL_stashcache for name '%"
       if (flags & HV_NAME_SETALL ? !!HvAUX(hv)->xhv_name_u.xhvnameu_name : !!name) {
         if (name && PL_stashcache) {
             DEBUG_o(Perl_deb(aTHX_ "hv_undef_flags clearing PL_stashcache for name '%"
-                             HEKf"'\n", HEKfARG(HvNAME_HEK(hv))));
+                             HEKf "'\n", HEKfARG(HvNAME_HEK(hv))));
            (void)hv_deletehek(PL_stashcache, HvNAME_HEK(hv), G_DISCARD);
         }
        hv_name_set(hv, NULL, 0, flags);
            (void)hv_deletehek(PL_stashcache, HvNAME_HEK(hv), G_DISCARD);
         }
        hv_name_set(hv, NULL, 0, flags);
@@ -1928,23 +2115,29 @@ Perl_hv_undef_flags(pTHX_ HV *hv, U32 flags)
 
     if (SvRMAGICAL(hv))
        mg_clear(MUTABLE_SV(hv));
 
     if (SvRMAGICAL(hv))
        mg_clear(MUTABLE_SV(hv));
-    if (save) LEAVE;
+
+    if (save) {
+        /* disarm hv's premature free guard */
+        if (LIKELY(PL_tmps_ix == orig_ix))
+            PL_tmps_ix--;
+        else
+            PL_tmps_stack[orig_ix] = &PL_sv_undef;
+        SvREFCNT_dec_NN(hv);
+    }
 }
 
 /*
 =for apidoc hv_fill
 
 }
 
 /*
 =for apidoc hv_fill
 
-Returns the number of hash buckets that
-happen to be in use.  This function is
-wrapped by the macro C<HvFILL>.
+Returns the number of hash buckets that happen to be in use.
+
+This function is wrapped by the macro C<HvFILL>.
 
 
-Previously this value was always stored in the HV structure, which created an
-overhead on every hash (and pretty much every object) for something that was
-rarely used.  Now we calculate it on demand the first
-time that it is needed, and cache it if that calculation
-is going to be costly to repeat.  The cached
-value is updated by insertions and deletions, but (currently) discarded if
-the hash is split.
+As of perl 5.25 this function is used only for debugging
+purposes, and the number of used hash buckets is not
+in any way cached, thus this function can be costly
+to execute as it must iterate over all the buckets in the
+hash.
 
 =cut
 */
 
 =cut
 */
@@ -1954,8 +2147,8 @@ Perl_hv_fill(pTHX_ HV *const hv)
 {
     STRLEN count = 0;
     HE **ents = HvARRAY(hv);
 {
     STRLEN count = 0;
     HE **ents = HvARRAY(hv);
-    struct xpvhv_aux *aux = SvOOK(hv) ? HvAUX(hv) : NULL;
 
 
+    PERL_UNUSED_CONTEXT;
     PERL_ARGS_ASSERT_HV_FILL;
 
     /* No keys implies no buckets used.
     PERL_ARGS_ASSERT_HV_FILL;
 
     /* No keys implies no buckets used.
@@ -1963,12 +2156,12 @@ Perl_hv_fill(pTHX_ HV *const hv)
     if (HvTOTALKEYS(hv) < 2)
         return HvTOTALKEYS(hv);
 
     if (HvTOTALKEYS(hv) < 2)
         return HvTOTALKEYS(hv);
 
-#ifndef DEBUGGING
-    if (aux && aux->xhv_fill_lazy)
-        return aux->xhv_fill_lazy;
-#endif
-
     if (ents) {
     if (ents) {
+        /* I wonder why we count down here...
+         * Is it some micro-optimisation?
+         * I would have thought counting up was better.
+         * - Yves
+         */
        HE *const *const last = ents + HvMAX(hv);
        count = last + 1 - ents;
 
        HE *const *const last = ents + HvMAX(hv);
        count = last + 1 - ents;
 
@@ -1977,16 +2170,6 @@ Perl_hv_fill(pTHX_ HV *const hv)
                --count;
        } while (++ents <= last);
     }
                --count;
        } while (++ents <= last);
     }
-    if (aux) {
-#ifdef DEBUGGING
-        if (aux->xhv_fill_lazy)
-            assert(aux->xhv_fill_lazy == count);
-#endif
-        aux->xhv_fill_lazy = count;
-    } else if (HvMAX(hv) >= HV_FILL_THRESHOLD) {
-        aux = hv_auxinit(hv);
-        aux->xhv_fill_lazy = count;
-    }        
     return count;
 }
 
     return count;
 }
 
@@ -2031,7 +2214,6 @@ S_hv_auxinit_internal(struct xpvhv_aux *iter) {
 #ifdef PERL_HASH_RANDOMIZE_KEYS
     iter->xhv_last_rand = iter->xhv_rand;
 #endif
 #ifdef PERL_HASH_RANDOMIZE_KEYS
     iter->xhv_last_rand = iter->xhv_rand;
 #endif
-    iter->xhv_fill_lazy = 0;
     iter->xhv_name_u.xhvnameu_name = 0;
     iter->xhv_name_count = 0;
     iter->xhv_backreferences = 0;
     iter->xhv_name_u.xhvnameu_name = 0;
     iter->xhv_name_count = 0;
     iter->xhv_backreferences = 0;
@@ -2080,8 +2262,8 @@ S_hv_auxinit(pTHX_ HV *hv) {
 =for apidoc hv_iterinit
 
 Prepares a starting point to traverse a hash table.  Returns the number of
 =for apidoc hv_iterinit
 
 Prepares a starting point to traverse a hash table.  Returns the number of
-keys in the hash (i.e. the same as C<HvUSEDKEYS(hv)>).  The return value is
-currently only meaningful for hashes without tie magic.
+keys in the hash, including placeholders (i.e. the same as C<HvTOTALKEYS(hv)>).
+The return value is currently only meaningful for hashes without tie magic.
 
 NOTE: Before version 5.004_65, C<hv_iterinit> used to return the number of
 hash buckets that happen to be in use.  If you still need that esoteric
 
 NOTE: Before version 5.004_65, C<hv_iterinit> used to return the number of
 hash buckets that happen to be in use.  If you still need that esoteric
@@ -2113,7 +2295,7 @@ Perl_hv_iterinit(pTHX_ HV *hv)
        hv_auxinit(hv);
     }
 
        hv_auxinit(hv);
     }
 
-    /* used to be xhv->xhv_fill before 5.004_65 */
+    /* note this includes placeholders! */
     return HvTOTALKEYS(hv);
 }
 
     return HvTOTALKEYS(hv);
 }
 
@@ -2194,7 +2376,6 @@ Perl_hv_eiter_set(pTHX_ HV *hv, HE *eiter) {
 void
 Perl_hv_name_set(pTHX_ HV *hv, const char *name, U32 len, U32 flags)
 {
 void
 Perl_hv_name_set(pTHX_ HV *hv, const char *name, U32 len, U32 flags)
 {
-    dVAR;
     struct xpvhv_aux *iter;
     U32 hash;
     HEK **spot;
     struct xpvhv_aux *iter;
     U32 hash;
     HEK **spot;
@@ -2202,24 +2383,24 @@ Perl_hv_name_set(pTHX_ HV *hv, const char *name, U32 len, U32 flags)
     PERL_ARGS_ASSERT_HV_NAME_SET;
 
     if (len > I32_MAX)
     PERL_ARGS_ASSERT_HV_NAME_SET;
 
     if (len > I32_MAX)
-       Perl_croak(aTHX_ "panic: hv name too long (%"UVuf")", (UV) len);
+       Perl_croak(aTHX_ "panic: hv name too long (%" UVuf ")", (UV) len);
 
     if (SvOOK(hv)) {
        iter = HvAUX(hv);
        if (iter->xhv_name_u.xhvnameu_name) {
            if(iter->xhv_name_count) {
              if(flags & HV_NAME_SETALL) {
 
     if (SvOOK(hv)) {
        iter = HvAUX(hv);
        if (iter->xhv_name_u.xhvnameu_name) {
            if(iter->xhv_name_count) {
              if(flags & HV_NAME_SETALL) {
-               HEK ** const name = HvAUX(hv)->xhv_name_u.xhvnameu_names;
-               HEK **hekp = name + (
+               HEK ** const this_name = HvAUX(hv)->xhv_name_u.xhvnameu_names;
+               HEK **hekp = this_name + (
                    iter->xhv_name_count < 0
                     ? -iter->xhv_name_count
                     :  iter->xhv_name_count
                   );
                    iter->xhv_name_count < 0
                     ? -iter->xhv_name_count
                     :  iter->xhv_name_count
                   );
-               while(hekp-- > name+1) 
+               while(hekp-- > this_name+1)
                    unshare_hek_or_pvn(*hekp, 0, 0, 0);
                /* The first elem may be null. */
                    unshare_hek_or_pvn(*hekp, 0, 0, 0);
                /* The first elem may be null. */
-               if(*name) unshare_hek_or_pvn(*name, 0, 0, 0);
-               Safefree(name);
+               if(*this_name) unshare_hek_or_pvn(*this_name, 0, 0, 0);
+               Safefree(this_name);
                 iter = HvAUX(hv); /* may been realloced */
                spot = &iter->xhv_name_u.xhvnameu_name;
                iter->xhv_name_count = 0;
                 iter = HvAUX(hv); /* may been realloced */
                spot = &iter->xhv_name_u.xhvnameu_name;
                iter->xhv_name_count = 0;
@@ -2291,7 +2472,7 @@ hek_eq_pvn_flags(pTHX_ const HEK *hek, const char* pv, const I32 pvlen, const U3
 =for apidoc hv_ename_add
 
 Adds a name to a stash's internal list of effective names.  See
 =for apidoc hv_ename_add
 
 Adds a name to a stash's internal list of effective names.  See
-C<hv_ename_delete>.
+C<L</hv_ename_delete>>.
 
 This is called when a stash is assigned to a new location in the symbol
 table.
 
 This is called when a stash is assigned to a new location in the symbol
 table.
@@ -2302,14 +2483,13 @@ table.
 void
 Perl_hv_ename_add(pTHX_ HV *hv, const char *name, U32 len, U32 flags)
 {
 void
 Perl_hv_ename_add(pTHX_ HV *hv, const char *name, U32 len, U32 flags)
 {
-    dVAR;
     struct xpvhv_aux *aux = SvOOK(hv) ? HvAUX(hv) : hv_auxinit(hv);
     U32 hash;
 
     PERL_ARGS_ASSERT_HV_ENAME_ADD;
 
     if (len > I32_MAX)
     struct xpvhv_aux *aux = SvOOK(hv) ? HvAUX(hv) : hv_auxinit(hv);
     U32 hash;
 
     PERL_ARGS_ASSERT_HV_ENAME_ADD;
 
     if (len > I32_MAX)
-       Perl_croak(aTHX_ "panic: hv name too long (%"UVuf")", (UV) len);
+       Perl_croak(aTHX_ "panic: hv name too long (%" UVuf ")", (UV) len);
 
     PERL_HASH(hash, name, len);
 
 
     PERL_HASH(hash, name, len);
 
@@ -2371,7 +2551,7 @@ Perl_hv_ename_delete(pTHX_ HV *hv, const char *name, U32 len, U32 flags)
     PERL_ARGS_ASSERT_HV_ENAME_DELETE;
 
     if (len > I32_MAX)
     PERL_ARGS_ASSERT_HV_ENAME_DELETE;
 
     if (len > I32_MAX)
-       Perl_croak(aTHX_ "panic: hv name too long (%"UVuf")", (UV) len);
+       Perl_croak(aTHX_ "panic: hv name too long (%" UVuf ")", (UV) len);
 
     if (!SvOOK(hv)) return;
 
 
     if (!SvOOK(hv)) return;
 
@@ -2408,9 +2588,10 @@ Perl_hv_ename_delete(pTHX_ HV *hv, const char *name, U32 len, U32 flags)
                return;
            }
        if (
                return;
            }
        if (
-           count > 0 && (HEK_UTF8(*namep) || (flags & SVf_UTF8)) 
+           count > 0 && ((HEK_UTF8(*namep) || (flags & SVf_UTF8)) 
                 ? hek_eq_pvn_flags(aTHX_ *namep, name, (I32)len, flags)
                : (HEK_LEN(*namep) == (I32)len && memEQ(HEK_KEY(*namep), name, len))
                 ? hek_eq_pvn_flags(aTHX_ *namep, name, (I32)len, flags)
                : (HEK_LEN(*namep) == (I32)len && memEQ(HEK_KEY(*namep), name, len))
+            )
        ) {
            aux->xhv_name_count = -count;
        }
        ) {
            aux->xhv_name_count = -count;
        }
@@ -2462,7 +2643,7 @@ hv_iternext is implemented as a macro in hv.h
 
 =for apidoc hv_iternext
 
 
 =for apidoc hv_iternext
 
-Returns entries from a hash iterator.  See C<hv_iterinit>.
+Returns entries from a hash iterator.  See C<L</hv_iterinit>>.
 
 You may call C<hv_delete> or C<hv_delete_ent> on the hash entry that the
 iterator currently points to, without losing your place or invalidating your
 
 You may call C<hv_delete> or C<hv_delete_ent> on the hash entry that the
 iterator currently points to, without losing your place or invalidating your
@@ -2474,8 +2655,9 @@ trigger the resource deallocation.
 
 =for apidoc hv_iternext_flags
 
 
 =for apidoc hv_iternext_flags
 
-Returns entries from a hash iterator.  See C<hv_iterinit> and C<hv_iternext>.
-The C<flags> value will normally be zero; if HV_ITERNEXT_WANTPLACEHOLDERS is
+Returns entries from a hash iterator.  See C<L</hv_iterinit>> and
+C<L</hv_iternext>>.
+The C<flags> value will normally be zero; if C<HV_ITERNEXT_WANTPLACEHOLDERS> is
 set the placeholders keys (for restricted hashes) will be returned in addition
 to normal keys.  By default placeholders are automatically skipped over.
 Currently a placeholder is implemented with a value that is
 set the placeholders keys (for restricted hashes) will be returned in addition
 to normal keys.  By default placeholders are automatically skipped over.
 Currently a placeholder is implemented with a value that is
@@ -2483,13 +2665,14 @@ C<&PL_sv_placeholder>.  Note that the implementation of placeholders and
 restricted hashes may change, and the implementation currently is
 insufficiently abstracted for any change to be tidy.
 
 restricted hashes may change, and the implementation currently is
 insufficiently abstracted for any change to be tidy.
 
+=for apidoc Amnh||HV_ITERNEXT_WANTPLACEHOLDERS
+
 =cut
 */
 
 HE *
 Perl_hv_iternext_flags(pTHX_ HV *hv, I32 flags)
 {
 =cut
 */
 
 HE *
 Perl_hv_iternext_flags(pTHX_ HV *hv, I32 flags)
 {
-    dVAR;
     XPVHV* xhv;
     HE *entry;
     HE *oldentry;
     XPVHV* xhv;
     HE *entry;
     HE *oldentry;
@@ -2640,7 +2823,7 @@ Perl_hv_iternext_flags(pTHX_ HV *hv, I32 flags)
 =for apidoc hv_iterkey
 
 Returns the key from the current position of the hash iterator.  See
 =for apidoc hv_iterkey
 
 Returns the key from the current position of the hash iterator.  See
-C<hv_iterinit>.
+C<L</hv_iterinit>>.
 
 =cut
 */
 
 =cut
 */
@@ -2668,7 +2851,7 @@ Perl_hv_iterkey(pTHX_ HE *entry, I32 *retlen)
 
 Returns the key as an C<SV*> from the current position of the hash
 iterator.  The return value will always be a mortal copy of the key.  Also
 
 Returns the key as an C<SV*> from the current position of the hash
 iterator.  The return value will always be a mortal copy of the key.  Also
-see C<hv_iterinit>.
+see C<L</hv_iterinit>>.
 
 =cut
 */
 
 =cut
 */
@@ -2685,7 +2868,7 @@ Perl_hv_iterkeysv(pTHX_ HE *entry)
 =for apidoc hv_iterval
 
 Returns the value from the current position of the hash iterator.  See
 =for apidoc hv_iterval
 
 Returns the value from the current position of the hash iterator.  See
-C<hv_iterkey>.
+C<L</hv_iterkey>>.
 
 =cut
 */
 
 =cut
 */
@@ -2736,7 +2919,7 @@ Now a macro in hv.h
 
 =for apidoc hv_magic
 
 
 =for apidoc hv_magic
 
-Adds magic to a hash.  See C<sv_magic>.
+Adds magic to a hash.  See C<L</sv_magic>>.
 
 =cut
 */
 
 =cut
 */
@@ -2853,7 +3036,7 @@ S_unshare_hek_or_pvn(pTHX_ const HEK *hek, const char *str, I32 len, U32 hash)
  * len and hash must both be valid for str.
  */
 HEK *
  * len and hash must both be valid for str.
  */
 HEK *
-Perl_share_hek(pTHX_ const char *str, I32 len, U32 hash)
+Perl_share_hek(pTHX_ const char *str, SSize_t len, U32 hash)
 {
     bool is_utf8 = FALSE;
     int flags = 0;
 {
     bool is_utf8 = FALSE;
     int flags = 0;
@@ -2875,7 +3058,6 @@ Perl_share_hek(pTHX_ const char *str, I32 len, U32 hash)
          we should flag that it needs upgrading on keys or each.  Also flag
          that we need share_hek_flags to free the string.  */
       if (str != save) {
          we should flag that it needs upgrading on keys or each.  Also flag
          that we need share_hek_flags to free the string.  */
       if (str != save) {
-          dVAR;
           PERL_HASH(hash, str, len);
           flags |= HVhek_WASUTF8 | HVhek_FREEKEY;
       }
           PERL_HASH(hash, str, len);
           flags |= HVhek_WASUTF8 | HVhek_FREEKEY;
       }
@@ -2885,7 +3067,7 @@ Perl_share_hek(pTHX_ const char *str, I32 len, U32 hash)
 }
 
 STATIC HEK *
 }
 
 STATIC HEK *
-S_share_hek_flags(pTHX_ const char *str, I32 len, U32 hash, int flags)
+S_share_hek_flags(pTHX_ const char *str, STRLEN len, U32 hash, int flags)
 {
     HE *entry;
     const int flags_masked = flags & HVhek_MASK;
 {
     HE *entry;
     const int flags_masked = flags & HVhek_MASK;
@@ -2894,6 +3076,10 @@ S_share_hek_flags(pTHX_ const char *str, I32 len, U32 hash, int flags)
 
     PERL_ARGS_ASSERT_SHARE_HEK_FLAGS;
 
 
     PERL_ARGS_ASSERT_SHARE_HEK_FLAGS;
 
+    if (UNLIKELY(len > (STRLEN) I32_MAX)) {
+        Perl_croak_nocontext("Sorry, hash keys must be smaller than 2**31 bytes");
+    }
+
     /* what follows is the moral equivalent of:
 
     if (!(Svp = hv_fetch(PL_strtab, str, len, FALSE)))
     /* what follows is the moral equivalent of:
 
     if (!(Svp = hv_fetch(PL_strtab, str, len, FALSE)))
@@ -2908,7 +3094,7 @@ S_share_hek_flags(pTHX_ const char *str, I32 len, U32 hash, int flags)
     for (;entry; entry = HeNEXT(entry)) {
        if (HeHASH(entry) != hash)              /* strings can't be equal */
            continue;
     for (;entry; entry = HeNEXT(entry)) {
        if (HeHASH(entry) != hash)              /* strings can't be equal */
            continue;
-       if (HeKLEN(entry) != len)
+       if (HeKLEN(entry) != (SSize_t) len)
            continue;
        if (HeKEY(entry) != str && memNE(HeKEY(entry),str,len)) /* is this it? */
            continue;
            continue;
        if (HeKEY(entry) != str && memNE(HeKEY(entry),str,len)) /* is this it? */
            continue;
@@ -3016,7 +3202,6 @@ Perl_hv_placeholders_set(pTHX_ HV *hv, I32 ph)
 STATIC SV *
 S_refcounted_he_value(pTHX_ const struct refcounted_he *he)
 {
 STATIC SV *
 S_refcounted_he_value(pTHX_ const struct refcounted_he *he)
 {
-    dVAR;
     SV *value;
 
     PERL_ARGS_ASSERT_REFCOUNTED_HE_VALUE;
     SV *value;
 
     PERL_ARGS_ASSERT_REFCOUNTED_HE_VALUE;
@@ -3049,30 +3234,29 @@ S_refcounted_he_value(pTHX_ const struct refcounted_he *he)
            SvUTF8_on(value);
        break;
     default:
            SvUTF8_on(value);
        break;
     default:
-       Perl_croak(aTHX_ "panic: refcounted_he_value bad flags %"UVxf,
+       Perl_croak(aTHX_ "panic: refcounted_he_value bad flags %" UVxf,
                   (UV)he->refcounted_he_data[0]);
     }
     return value;
 }
 
 /*
                   (UV)he->refcounted_he_data[0]);
     }
     return value;
 }
 
 /*
-=for apidoc m|HV *|refcounted_he_chain_2hv|const struct refcounted_he *c|U32 flags
+=for apidoc refcounted_he_chain_2hv
 
 Generates and returns a C<HV *> representing the content of a
 C<refcounted_he> chain.
 
 Generates and returns a C<HV *> representing the content of a
 C<refcounted_he> chain.
-I<flags> is currently unused and must be zero.
+C<flags> is currently unused and must be zero.
 
 =cut
 */
 HV *
 Perl_refcounted_he_chain_2hv(pTHX_ const struct refcounted_he *chain, U32 flags)
 {
 
 =cut
 */
 HV *
 Perl_refcounted_he_chain_2hv(pTHX_ const struct refcounted_he *chain, U32 flags)
 {
-    dVAR;
     HV *hv;
     U32 placeholders, max;
 
     if (flags)
     HV *hv;
     U32 placeholders, max;
 
     if (flags)
-       Perl_croak(aTHX_ "panic: refcounted_he_chain_2hv bad flags %"UVxf,
+       Perl_croak(aTHX_ "panic: refcounted_he_chain_2hv bad flags %" UVxf,
            (UV)flags);
 
     /* We could chase the chain once to get an idea of the number of keys,
            (UV)flags);
 
     /* We could chase the chain once to get an idea of the number of keys,
@@ -3164,12 +3348,12 @@ Perl_refcounted_he_chain_2hv(pTHX_ const struct refcounted_he *chain, U32 flags)
 }
 
 /*
 }
 
 /*
-=for apidoc m|SV *|refcounted_he_fetch_pvn|const struct refcounted_he *chain|const char *keypv|STRLEN keylen|U32 hash|U32 flags
+=for apidoc refcounted_he_fetch_pvn
 
 Search along a C<refcounted_he> chain for an entry with the key specified
 
 Search along a C<refcounted_he> chain for an entry with the key specified
-by I<keypv> and I<keylen>.  If I<flags> has the C<REFCOUNTED_HE_KEY_UTF8>
+by C<keypv> and C<keylen>.  If C<flags> has the C<REFCOUNTED_HE_KEY_UTF8>
 bit set, the key octets are interpreted as UTF-8, otherwise they
 bit set, the key octets are interpreted as UTF-8, otherwise they
-are interpreted as Latin-1.  I<hash> is a precomputed hash of the key
+are interpreted as Latin-1.  C<hash> is a precomputed hash of the key
 string, or zero if it has not been precomputed.  Returns a mortal scalar
 representing the value associated with the key, or C<&PL_sv_placeholder>
 if there is no value associated with the key.
 string, or zero if it has not been precomputed.  Returns a mortal scalar
 representing the value associated with the key, or C<&PL_sv_placeholder>
 if there is no value associated with the key.
@@ -3181,12 +3365,11 @@ SV *
 Perl_refcounted_he_fetch_pvn(pTHX_ const struct refcounted_he *chain,
                         const char *keypv, STRLEN keylen, U32 hash, U32 flags)
 {
 Perl_refcounted_he_fetch_pvn(pTHX_ const struct refcounted_he *chain,
                         const char *keypv, STRLEN keylen, U32 hash, U32 flags)
 {
-    dVAR;
     U8 utf8_flag;
     PERL_ARGS_ASSERT_REFCOUNTED_HE_FETCH_PVN;
 
     if (flags & ~(REFCOUNTED_HE_KEY_UTF8|REFCOUNTED_HE_EXISTS))
     U8 utf8_flag;
     PERL_ARGS_ASSERT_REFCOUNTED_HE_FETCH_PVN;
 
     if (flags & ~(REFCOUNTED_HE_KEY_UTF8|REFCOUNTED_HE_EXISTS))
-       Perl_croak(aTHX_ "panic: refcounted_he_fetch_pvn bad flags %"UVxf,
+       Perl_croak(aTHX_ "panic: refcounted_he_fetch_pvn bad flags %" UVxf,
            (UV)flags);
     if (!chain)
        goto ret;
            (UV)flags);
     if (!chain)
        goto ret;
@@ -3217,7 +3400,7 @@ Perl_refcounted_he_fetch_pvn(pTHX_ const struct refcounted_he *chain,
                 }
                 else {
                     p++;
                 }
                 else {
                     p++;
-                    *q = (char) TWO_BYTE_UTF8_TO_NATIVE(c, *p);
+                    *q = (char) EIGHT_BIT_UTF8_TO_NATIVE(c, *p);
                 }
            }
        }
                 }
            }
        }
@@ -3254,7 +3437,7 @@ Perl_refcounted_he_fetch_pvn(pTHX_ const struct refcounted_he *chain,
 }
 
 /*
 }
 
 /*
-=for apidoc m|SV *|refcounted_he_fetch_pv|const struct refcounted_he *chain|const char *key|U32 hash|U32 flags
+=for apidoc refcounted_he_fetch_pv
 
 Like L</refcounted_he_fetch_pvn>, but takes a nul-terminated string
 instead of a string/length pair.
 
 Like L</refcounted_he_fetch_pvn>, but takes a nul-terminated string
 instead of a string/length pair.
@@ -3271,7 +3454,7 @@ Perl_refcounted_he_fetch_pv(pTHX_ const struct refcounted_he *chain,
 }
 
 /*
 }
 
 /*
-=for apidoc m|SV *|refcounted_he_fetch_sv|const struct refcounted_he *chain|SV *key|U32 hash|U32 flags
+=for apidoc refcounted_he_fetch_sv
 
 Like L</refcounted_he_fetch_pvn>, but takes a Perl scalar instead of a
 string/length pair.
 
 Like L</refcounted_he_fetch_pvn>, but takes a Perl scalar instead of a
 string/length pair.
@@ -3287,7 +3470,7 @@ Perl_refcounted_he_fetch_sv(pTHX_ const struct refcounted_he *chain,
     STRLEN keylen;
     PERL_ARGS_ASSERT_REFCOUNTED_HE_FETCH_SV;
     if (flags & REFCOUNTED_HE_KEY_UTF8)
     STRLEN keylen;
     PERL_ARGS_ASSERT_REFCOUNTED_HE_FETCH_SV;
     if (flags & REFCOUNTED_HE_KEY_UTF8)
-       Perl_croak(aTHX_ "panic: refcounted_he_fetch_sv bad flags %"UVxf,
+       Perl_croak(aTHX_ "panic: refcounted_he_fetch_sv bad flags %" UVxf,
            (UV)flags);
     keypv = SvPV_const(key, keylen);
     if (SvUTF8(key))
            (UV)flags);
     keypv = SvPV_const(key, keylen);
     if (SvUTF8(key))
@@ -3298,7 +3481,7 @@ Perl_refcounted_he_fetch_sv(pTHX_ const struct refcounted_he *chain,
 }
 
 /*
 }
 
 /*
-=for apidoc m|struct refcounted_he *|refcounted_he_new_pvn|struct refcounted_he *parent|const char *keypv|STRLEN keylen|U32 hash|SV *value|U32 flags
+=for apidoc refcounted_he_new_pvn
 
 Creates a new C<refcounted_he>.  This consists of a single key/value
 pair and a reference to an existing C<refcounted_he> chain (which may
 
 Creates a new C<refcounted_he>.  This consists of a single key/value
 pair and a reference to an existing C<refcounted_he> chain (which may
@@ -3306,25 +3489,25 @@ be empty), and thus forms a longer chain.  When using the longer chain,
 the new key/value pair takes precedence over any entry for the same key
 further along the chain.
 
 the new key/value pair takes precedence over any entry for the same key
 further along the chain.
 
-The new key is specified by I<keypv> and I<keylen>.  If I<flags> has
+The new key is specified by C<keypv> and C<keylen>.  If C<flags> has
 the C<REFCOUNTED_HE_KEY_UTF8> bit set, the key octets are interpreted
 the C<REFCOUNTED_HE_KEY_UTF8> bit set, the key octets are interpreted
-as UTF-8, otherwise they are interpreted as Latin-1.  I<hash> is
+as UTF-8, otherwise they are interpreted as Latin-1.  C<hash> is
 a precomputed hash of the key string, or zero if it has not been
 precomputed.
 
 a precomputed hash of the key string, or zero if it has not been
 precomputed.
 
-I<value> is the scalar value to store for this key.  I<value> is copied
+C<value> is the scalar value to store for this key.  C<value> is copied
 by this function, which thus does not take ownership of any reference
 to it, and later changes to the scalar will not be reflected in the
 value visible in the C<refcounted_he>.  Complex types of scalar will not
 be stored with referential integrity, but will be coerced to strings.
 by this function, which thus does not take ownership of any reference
 to it, and later changes to the scalar will not be reflected in the
 value visible in the C<refcounted_he>.  Complex types of scalar will not
 be stored with referential integrity, but will be coerced to strings.
-I<value> may be either null or C<&PL_sv_placeholder> to indicate that no
+C<value> may be either null or C<&PL_sv_placeholder> to indicate that no
 value is to be associated with the key; this, as with any non-null value,
 takes precedence over the existence of a value for the key further along
 the chain.
 
 value is to be associated with the key; this, as with any non-null value,
 takes precedence over the existence of a value for the key further along
 the chain.
 
-I<parent> points to the rest of the C<refcounted_he> chain to be
+C<parent> points to the rest of the C<refcounted_he> chain to be
 attached to the new C<refcounted_he>.  This function takes ownership
 attached to the new C<refcounted_he>.  This function takes ownership
-of one reference to I<parent>, and returns one reference to the new
+of one reference to C<parent>, and returns one reference to the new
 C<refcounted_he>.
 
 =cut
 C<refcounted_he>.
 
 =cut
@@ -3334,7 +3517,6 @@ struct refcounted_he *
 Perl_refcounted_he_new_pvn(pTHX_ struct refcounted_he *parent,
        const char *keypv, STRLEN keylen, U32 hash, SV *value, U32 flags)
 {
 Perl_refcounted_he_new_pvn(pTHX_ struct refcounted_he *parent,
        const char *keypv, STRLEN keylen, U32 hash, SV *value, U32 flags)
 {
-    dVAR;
     STRLEN value_len = 0;
     const char *value_p = NULL;
     bool is_pv;
     STRLEN value_len = 0;
     const char *value_p = NULL;
     bool is_pv;
@@ -3393,7 +3575,7 @@ Perl_refcounted_he_new_pvn(pTHX_ struct refcounted_he *parent,
                 }
                 else {
                     p++;
                 }
                 else {
                     p++;
-                    *q = (char) TWO_BYTE_UTF8_TO_NATIVE(c, *p);
+                    *q = (char) EIGHT_BIT_UTF8_TO_NATIVE(c, *p);
                 }
            }
        }
                 }
            }
        }
@@ -3442,7 +3624,7 @@ Perl_refcounted_he_new_pvn(pTHX_ struct refcounted_he *parent,
 }
 
 /*
 }
 
 /*
-=for apidoc m|struct refcounted_he *|refcounted_he_new_pv|struct refcounted_he *parent|const char *key|U32 hash|SV *value|U32 flags
+=for apidoc refcounted_he_new_pv
 
 Like L</refcounted_he_new_pvn>, but takes a nul-terminated string instead
 of a string/length pair.
 
 Like L</refcounted_he_new_pvn>, but takes a nul-terminated string instead
 of a string/length pair.
@@ -3459,7 +3641,7 @@ Perl_refcounted_he_new_pv(pTHX_ struct refcounted_he *parent,
 }
 
 /*
 }
 
 /*
-=for apidoc m|struct refcounted_he *|refcounted_he_new_sv|struct refcounted_he *parent|SV *key|U32 hash|SV *value|U32 flags
+=for apidoc refcounted_he_new_sv
 
 Like L</refcounted_he_new_pvn>, but takes a Perl scalar instead of a
 string/length pair.
 
 Like L</refcounted_he_new_pvn>, but takes a Perl scalar instead of a
 string/length pair.
@@ -3475,7 +3657,7 @@ Perl_refcounted_he_new_sv(pTHX_ struct refcounted_he *parent,
     STRLEN keylen;
     PERL_ARGS_ASSERT_REFCOUNTED_HE_NEW_SV;
     if (flags & REFCOUNTED_HE_KEY_UTF8)
     STRLEN keylen;
     PERL_ARGS_ASSERT_REFCOUNTED_HE_NEW_SV;
     if (flags & REFCOUNTED_HE_KEY_UTF8)
-       Perl_croak(aTHX_ "panic: refcounted_he_new_sv bad flags %"UVxf,
+       Perl_croak(aTHX_ "panic: refcounted_he_new_sv bad flags %" UVxf,
            (UV)flags);
     keypv = SvPV_const(key, keylen);
     if (SvUTF8(key))
            (UV)flags);
     keypv = SvPV_const(key, keylen);
     if (SvUTF8(key))
@@ -3486,7 +3668,7 @@ Perl_refcounted_he_new_sv(pTHX_ struct refcounted_he *parent,
 }
 
 /*
 }
 
 /*
-=for apidoc m|void|refcounted_he_free|struct refcounted_he *he
+=for apidoc refcounted_he_free
 
 Decrements the reference count of a C<refcounted_he> by one.  If the
 reference count reaches zero the structure's memory is freed, which
 
 Decrements the reference count of a C<refcounted_he> by one.  If the
 reference count reaches zero the structure's memory is freed, which
@@ -3500,7 +3682,6 @@ no action occurs in this case.
 void
 Perl_refcounted_he_free(pTHX_ struct refcounted_he *he) {
 #ifdef USE_ITHREADS
 void
 Perl_refcounted_he_free(pTHX_ struct refcounted_he *he) {
 #ifdef USE_ITHREADS
-    dVAR;
 #endif
     PERL_UNUSED_CONTEXT;
 
 #endif
     PERL_UNUSED_CONTEXT;
 
@@ -3526,7 +3707,7 @@ Perl_refcounted_he_free(pTHX_ struct refcounted_he *he) {
 }
 
 /*
 }
 
 /*
-=for apidoc m|struct refcounted_he *|refcounted_he_inc|struct refcounted_he *he
+=for apidoc refcounted_he_inc
 
 Increment the reference count of a C<refcounted_he>.  The pointer to the
 C<refcounted_he> is also returned.  It is safe to pass a null pointer
 
 Increment the reference count of a C<refcounted_he>.  The pointer to the
 C<refcounted_he> is also returned.  It is safe to pass a null pointer
@@ -3539,7 +3720,6 @@ struct refcounted_he *
 Perl_refcounted_he_inc(pTHX_ struct refcounted_he *he)
 {
 #ifdef USE_ITHREADS
 Perl_refcounted_he_inc(pTHX_ struct refcounted_he *he)
 {
 #ifdef USE_ITHREADS
-    dVAR;
 #endif
     PERL_UNUSED_CONTEXT;
     if (he) {
 #endif
     PERL_UNUSED_CONTEXT;
     if (he) {
@@ -3551,10 +3731,17 @@ Perl_refcounted_he_inc(pTHX_ struct refcounted_he *he)
 }
 
 /*
 }
 
 /*
+=for apidoc_section $COP
 =for apidoc cop_fetch_label
 
 =for apidoc cop_fetch_label
 
-Returns the label attached to a cop.
-The flags pointer may be set to C<SVf_UTF8> or 0.
+Returns the label attached to a cop, and stores its length in bytes into
+C<*len>.
+Upon return, C<*flags> will be set to either C<SVf_UTF8> or 0.
+
+Alternatively, use the macro C<L</CopLABEL_len_flags>>;
+or if you don't need to know if the label is UTF-8 or not, the macro
+C<L</CopLABEL_len>>;
+or if you additionally dont need to know the length, C<L</CopLABEL>>.
 
 =cut
 */
 
 =cut
 */
@@ -3601,7 +3788,7 @@ Perl_cop_fetch_label(pTHX_ COP *const cop, STRLEN *len, U32 *flags) {
 
 Save a label into a C<cop_hints_hash>.
 You need to set flags to C<SVf_UTF8>
 
 Save a label into a C<cop_hints_hash>.
 You need to set flags to C<SVf_UTF8>
-for a utf-8 label.
+for a UTF-8 label.  Any other flag is ignored.
 
 =cut
 */
 
 =cut
 */
@@ -3624,6 +3811,7 @@ Perl_cop_store_label(pTHX_ COP *const cop, const char *label, STRLEN len,
 }
 
 /*
 }
 
 /*
+=for apidoc_section $HV
 =for apidoc hv_assert
 
 Check that a hash is in an internally consistent state.
 =for apidoc hv_assert
 
 Check that a hash is in an internally consistent state.
@@ -3636,7 +3824,6 @@ Check that a hash is in an internally consistent state.
 void
 Perl_hv_assert(pTHX_ HV *hv)
 {
 void
 Perl_hv_assert(pTHX_ HV *hv)
 {
-    dVAR;
     HE* entry;
     int withflags = 0;
     int placeholders = 0;
     HE* entry;
     int withflags = 0;
     int placeholders = 0;