This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
$^S almost entirely broken with 5.6.1
[perl5.git] / hv.c
diff --git a/hv.c b/hv.c
index e38c785..14b9682 100644 (file)
--- a/hv.c
+++ b/hv.c
@@ -1,6 +1,6 @@
 /*    hv.c
  *
- *    Copyright (c) 1991-1999, Larry Wall
+ *    Copyright (c) 1991-2001, Larry Wall
  *
  *    You may distribute under the terms of either the GNU General Public
  *    License or the Artistic License, as specified in the README file.
@@ -15,6 +15,7 @@
 #define PERL_IN_HV_C
 #include "perl.h"
 
+
 STATIC HE*
 S_new_he(pTHX)
 {
@@ -42,9 +43,14 @@ S_more_he(pTHX)
 {
     register HE* he;
     register HE* heend;
-    New(54, PL_he_root, 1008/sizeof(HE), HE);
-    he = PL_he_root;
+    XPV *ptr;
+    New(54, ptr, 1008/sizeof(XPV), XPV);
+    ptr->xpv_pv = (char*)PL_he_arenaroot;
+    PL_he_arenaroot = ptr;
+
+    he = (HE*)ptr;
     heend = &he[1008 / sizeof(HE) - 1];
+    PL_he_root = ++he;
     while (he < heend) {
         HeNEXT(he) = (HE*)(he + 1);
         he++;
@@ -52,25 +58,44 @@ S_more_he(pTHX)
     HeNEXT(he) = 0;
 }
 
+#ifdef PURIFY
+
+#define new_HE() (HE*)safemalloc(sizeof(HE))
+#define del_HE(p) safefree((char*)p)
+
+#else
+
+#define new_HE() new_he()
+#define del_HE(p) del_he(p)
+
+#endif
+
 STATIC HEK *
 S_save_hek(pTHX_ const char *str, I32 len, U32 hash)
 {
     char *k;
     register HEK *hek;
-    
+    bool is_utf8 = FALSE;
+
+    if (len < 0) {
+      len = -len;
+      is_utf8 = TRUE;
+    }
+
     New(54, k, HEK_BASESIZE + len + 1, char);
     hek = (HEK*)k;
     Copy(str, HEK_KEY(hek), len, char);
-    *(HEK_KEY(hek) + len) = '\0';
     HEK_LEN(hek) = len;
     HEK_HASH(hek) = hash;
+    HEK_UTF8(hek) = (char)is_utf8;
     return hek;
 }
 
 void
 Perl_unshare_hek(pTHX_ HEK *hek)
 {
-    unsharepvn(HEK_KEY(hek),HEK_LEN(hek),HEK_HASH(hek));
+    unsharepvn(HEK_KEY(hek),HEK_UTF8(hek)?-HEK_LEN(hek):HEK_LEN(hek),
+               HEK_HASH(hek));
 }
 
 #if defined(USE_ITHREADS)
@@ -81,14 +106,22 @@ Perl_he_dup(pTHX_ HE *e, bool shared)
 
     if (!e)
        return Nullhe;
-    ret = new_he();
-    HeNEXT(ret) = (HE*)NULL;
+    /* look for it in the table first */
+    ret = (HE*)ptr_table_fetch(PL_ptr_table, e);
+    if (ret)
+       return ret;
+
+    /* create anew and remember what it is */
+    ret = new_HE();
+    ptr_table_store(PL_ptr_table, e, ret);
+
+    HeNEXT(ret) = he_dup(HeNEXT(e),shared);
     if (HeKLEN(e) == HEf_SVKEY)
        HeKEY_sv(ret) = SvREFCNT_inc(sv_dup(HeKEY_sv(e)));
     else if (shared)
-       HeKEY_hek(ret) = share_hek(HeKEY(e), HeKLEN(e), HeHASH(e));
+       HeKEY_hek(ret) = share_hek(HeKEY(e), HeKLEN_UTF8(e), HeHASH(e));
     else
-       HeKEY_hek(ret) = save_hek(HeKEY(e), HeKLEN(e), HeHASH(e));
+       HeKEY_hek(ret) = save_hek(HeKEY(e), HeKLEN_UTF8(e), HeHASH(e));
     HeVAL(ret) = SvREFCNT_inc(sv_dup(HeVAL(e)));
     return ret;
 }
@@ -97,27 +130,47 @@ Perl_he_dup(pTHX_ HE *e, bool shared)
 /* (klen == HEf_SVKEY) is special for MAGICAL hv entries, meaning key slot
  * contains an SV* */
 
+/*
+=for apidoc hv_fetch
+
+Returns the SV which corresponds to the specified key in the hash.  The
+C<klen> is the length of the key.  If C<lval> is set then the fetch will be
+part of a store.  Check that the return value is non-null before
+dereferencing it to a C<SV*>.
+
+See L<perlguts/"Understanding the Magic of Tied Hashes and Arrays"> for more
+information on how to use this function on tied hashes.
+
+=cut
+*/
+
 SV**
-Perl_hv_fetch(pTHX_ HV *hv, const char *key, U32 klen, I32 lval)
+Perl_hv_fetch(pTHX_ HV *hv, const char *key, I32 klen, I32 lval)
 {
     register XPVHV* xhv;
     register U32 hash;
     register HE *entry;
     SV *sv;
+    bool is_utf8 = FALSE;
+    const char *keysave = key;
 
     if (!hv)
        return 0;
 
+    if (klen < 0) {
+      klen = -klen;
+      is_utf8 = TRUE;
+    }
+
     if (SvRMAGICAL(hv)) {
-       if (mg_find((SV*)hv,'P')) {
-           dTHR;
+       if (mg_find((SV*)hv, PERL_MAGIC_tied) || SvGMAGICAL((SV*)hv)) {
            sv = sv_newmortal();
            mg_copy((SV*)hv, sv, key, klen);
            PL_hv_fetch_sv = sv;
            return &PL_hv_fetch_sv;
        }
 #ifdef ENV_IS_CASELESS
-       else if (mg_find((SV*)hv,'E')) {
+       else if (mg_find((SV*)hv, PERL_MAGIC_env)) {
            U32 i;
            for (i = 0; i < klen; ++i)
                if (isLOWER(key[i])) {
@@ -133,7 +186,7 @@ Perl_hv_fetch(pTHX_ HV *hv, const char *key, U32 klen, I32 lval)
 
     xhv = (XPVHV*)SvANY(hv);
     if (!xhv->xhv_array) {
-       if (lval 
+       if (lval
 #ifdef DYNAMIC_ENV_FETCH  /* if it's an %ENV lookup, we may get it on the fly */
                 || (HvNAME(hv) && strEQ(HvNAME(hv),ENV_HV_NAME))
 #endif
@@ -144,6 +197,14 @@ Perl_hv_fetch(pTHX_ HV *hv, const char *key, U32 klen, I32 lval)
            return 0;
     }
 
+    if (is_utf8 && !(PL_hints & HINT_UTF8_DISTINCT)) {
+       STRLEN tmplen = klen;
+       /* Just casting the &klen to (STRLEN) won't work well
+        * if STRLEN and I32 are of different widths. --jhi */
+       key = (char*)bytes_from_utf8((U8*)key, &tmplen, &is_utf8);
+       klen = tmplen;
+    }
+
     PERL_HASH(hash, key, klen);
 
     entry = ((HE**)xhv->xhv_array)[hash & (I32) xhv->xhv_max];
@@ -152,8 +213,12 @@ Perl_hv_fetch(pTHX_ HV *hv, const char *key, U32 klen, I32 lval)
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (memNE(HeKEY(entry),key,klen))       /* is this it? */
+       if (HeKEY(entry) != key && memNE(HeKEY(entry),key,klen))        /* is this it? */
            continue;
+       if (HeKUTF8(entry) != (char)is_utf8)
+           continue;
+       if (key != keysave)
+           Safefree(key);
        return &HeVAL(entry);
     }
 #ifdef DYNAMIC_ENV_FETCH  /* %ENV lookup?  If so, try to fetch the value now */
@@ -163,19 +228,46 @@ Perl_hv_fetch(pTHX_ HV *hv, const char *key, U32 klen, I32 lval)
        if (env) {
            sv = newSVpvn(env,len);
            SvTAINTED_on(sv);
+           if (key != keysave)
+               Safefree(key);
            return hv_store(hv,key,klen,sv,hash);
        }
     }
 #endif
     if (lval) {                /* gonna assign to this, so it better be there */
        sv = NEWSV(61,0);
-       return hv_store(hv,key,klen,sv,hash);
+       if (key != keysave) { /* must be is_utf8 == 0 */
+           SV **ret = hv_store(hv,key,klen,sv,hash);
+           Safefree(key);
+           return ret;
+       }
+       else
+           return hv_store(hv,key,is_utf8?-klen:klen,sv,hash);
     }
+    if (key != keysave)
+       Safefree(key);
     return 0;
 }
 
 /* returns a HE * structure with the all fields set */
 /* note that hent_val will be a mortal sv for MAGICAL hashes */
+/*
+=for apidoc hv_fetch_ent
+
+Returns the hash entry which corresponds to the specified key in the hash.
+C<hash> must be a valid precomputed hash number for the given C<key>, or 0
+if you want the function to compute it.  IF C<lval> is set then the fetch
+will be part of a store.  Make sure the return value is non-null before
+accessing it.  The return value when C<tb> is a tied hash is a pointer to a
+static location, so be sure to make a copy of the structure if you need to
+store it somewhere.
+
+See L<perlguts/"Understanding the Magic of Tied Hashes and Arrays"> for more
+information on how to use this function on tied hashes.
+
+=cut
+*/
+
 HE *
 Perl_hv_fetch_ent(pTHX_ HV *hv, SV *keysv, I32 lval, register U32 hash)
 {
@@ -184,13 +276,14 @@ Perl_hv_fetch_ent(pTHX_ HV *hv, SV *keysv, I32 lval, register U32 hash)
     STRLEN klen;
     register HE *entry;
     SV *sv;
+    bool is_utf8;
+    char *keysave;
 
     if (!hv)
        return 0;
 
     if (SvRMAGICAL(hv)) {
-       if (mg_find((SV*)hv,'P')) {
-           dTHR;
+       if (mg_find((SV*)hv, PERL_MAGIC_tied) || SvGMAGICAL((SV*)hv)) {
            sv = sv_newmortal();
            keysv = sv_2mortal(newSVsv(keysv));
            mg_copy((SV*)hv, sv, (char*)keysv, HEf_SVKEY);
@@ -204,7 +297,7 @@ Perl_hv_fetch_ent(pTHX_ HV *hv, SV *keysv, I32 lval, register U32 hash)
            return &PL_hv_fetch_ent_mh;
        }
 #ifdef ENV_IS_CASELESS
-       else if (mg_find((SV*)hv,'E')) {
+       else if (mg_find((SV*)hv, PERL_MAGIC_env)) {
            U32 i;
            key = SvPV(keysv, klen);
            for (i = 0; i < klen; ++i)
@@ -222,7 +315,7 @@ Perl_hv_fetch_ent(pTHX_ HV *hv, SV *keysv, I32 lval, register U32 hash)
 
     xhv = (XPVHV*)SvANY(hv);
     if (!xhv->xhv_array) {
-       if (lval 
+       if (lval
 #ifdef DYNAMIC_ENV_FETCH  /* if it's an %ENV lookup, we may get it on the fly */
                 || (HvNAME(hv) && strEQ(HvNAME(hv),ENV_HV_NAME))
 #endif
@@ -233,8 +326,12 @@ Perl_hv_fetch_ent(pTHX_ HV *hv, SV *keysv, I32 lval, register U32 hash)
            return 0;
     }
 
-    key = SvPV(keysv, klen);
-    
+    keysave = key = SvPV(keysv, klen);
+    is_utf8 = (SvUTF8(keysv)!=0);
+
+    if (is_utf8 && !(PL_hints & HINT_UTF8_DISTINCT))
+       key = (char*)bytes_from_utf8((U8*)key, &klen, &is_utf8);
+
     if (!hash)
        PERL_HASH(hash, key, klen);
 
@@ -244,8 +341,12 @@ Perl_hv_fetch_ent(pTHX_ HV *hv, SV *keysv, I32 lval, register U32 hash)
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (memNE(HeKEY(entry),key,klen))       /* is this it? */
+       if (HeKEY(entry) != key && memNE(HeKEY(entry),key,klen))        /* is this it? */
            continue;
+       if (HeKUTF8(entry) != (char)is_utf8)
+           continue;
+       if (key != keysave)
+           Safefree(key);
        return entry;
     }
 #ifdef DYNAMIC_ENV_FETCH  /* %ENV lookup?  If so, try to fetch the value now */
@@ -259,6 +360,8 @@ Perl_hv_fetch_ent(pTHX_ HV *hv, SV *keysv, I32 lval, register U32 hash)
        }
     }
 #endif
+    if (key != keysave)
+       Safefree(key);
     if (lval) {                /* gonna assign to this, so it better be there */
        sv = NEWSV(61,0);
        return hv_store_ent(hv,keysv,sv,hash);
@@ -276,8 +379,8 @@ S_hv_magic_check(pTHX_ HV *hv, bool *needs_copy, bool *needs_store)
        if (isUPPER(mg->mg_type)) {
            *needs_copy = TRUE;
            switch (mg->mg_type) {
-           case 'P':
-           case 'S':
+           case PERL_MAGIC_tied:
+           case PERL_MAGIC_sig:
                *needs_store = FALSE;
            }
        }
@@ -285,17 +388,42 @@ S_hv_magic_check(pTHX_ HV *hv, bool *needs_copy, bool *needs_store)
     }
 }
 
+/*
+=for apidoc hv_store
+
+Stores an SV in a hash.  The hash key is specified as C<key> and C<klen> is
+the length of the key.  The C<hash> parameter is the precomputed hash
+value; if it is zero then Perl will compute it.  The return value will be
+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
+the call, and decrementing it if the function returned NULL.
+
+See L<perlguts/"Understanding the Magic of Tied Hashes and Arrays"> for more
+information on how to use this function on tied hashes.
+
+=cut
+*/
+
 SV**
-Perl_hv_store(pTHX_ HV *hv, const char *key, U32 klen, SV *val, register U32 hash)
+Perl_hv_store(pTHX_ HV *hv, const char *key, I32 klen, SV *val, register U32 hash)
 {
     register XPVHV* xhv;
     register I32 i;
     register HE *entry;
     register HE **oentry;
+    bool is_utf8 = FALSE;
+    const char *keysave = key;
 
     if (!hv)
        return 0;
 
+    if (klen < 0) {
+      klen = -klen;
+      is_utf8 = TRUE;
+    }
+
     xhv = (XPVHV*)SvANY(hv);
     if (SvMAGICAL(hv)) {
        bool needs_copy;
@@ -306,14 +434,21 @@ Perl_hv_store(pTHX_ HV *hv, const char *key, U32 klen, SV *val, register U32 has
            if (!xhv->xhv_array && !needs_store)
                return 0;
 #ifdef ENV_IS_CASELESS
-           else if (mg_find((SV*)hv,'E')) {
-               SV *sv = sv_2mortal(newSVpvn(key,klen));
-               key = strupr(SvPVX(sv));
+           else if (mg_find((SV*)hv, PERL_MAGIC_env)) {
+                key = savepvn(key,klen);
+               key = strupr(key);
                hash = 0;
            }
 #endif
        }
     }
+    if (is_utf8 && !(PL_hints & HINT_UTF8_DISTINCT)) {
+       STRLEN tmplen = klen;
+       /* See the note in hv_fetch(). --jhi */
+       key = (char*)bytes_from_utf8((U8*)key, &tmplen, &is_utf8);
+       klen = tmplen;
+    }
+
     if (!hash)
        PERL_HASH(hash, key, klen);
 
@@ -329,18 +464,24 @@ Perl_hv_store(pTHX_ HV *hv, const char *key, U32 klen, SV *val, register U32 has
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (memNE(HeKEY(entry),key,klen))       /* is this it? */
+       if (HeKEY(entry) != key && memNE(HeKEY(entry),key,klen))        /* is this it? */
+           continue;
+       if (HeKUTF8(entry) != (char)is_utf8)
            continue;
        SvREFCNT_dec(HeVAL(entry));
        HeVAL(entry) = val;
+       if (key != keysave)
+           Safefree(key);
        return &HeVAL(entry);
     }
 
-    entry = new_he();
+    entry = new_HE();
     if (HvSHAREKEYS(hv))
-       HeKEY_hek(entry) = share_hek(key, klen, hash);
+       HeKEY_hek(entry) = share_hek(key, is_utf8?-klen:klen, hash);
     else                                       /* gotta do the real thing */
-       HeKEY_hek(entry) = save_hek(key, klen, hash);
+       HeKEY_hek(entry) = save_hek(key, is_utf8?-klen:klen, hash);
+    if (key != keysave)
+       Safefree(key);
     HeVAL(entry) = val;
     HeNEXT(entry) = *oentry;
     *oentry = entry;
@@ -355,6 +496,25 @@ Perl_hv_store(pTHX_ HV *hv, const char *key, U32 klen, SV *val, register U32 has
     return &HeVAL(entry);
 }
 
+/*
+=for apidoc hv_store_ent
+
+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
+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.
+
+See L<perlguts/"Understanding the Magic of Tied Hashes and Arrays"> for more
+information on how to use this function on tied hashes.
+
+=cut
+*/
+
 HE *
 Perl_hv_store_ent(pTHX_ HV *hv, SV *keysv, SV *val, register U32 hash)
 {
@@ -364,13 +524,14 @@ Perl_hv_store_ent(pTHX_ HV *hv, SV *keysv, SV *val, register U32 hash)
     register I32 i;
     register HE *entry;
     register HE **oentry;
+    bool is_utf8;
+    char *keysave;
 
     if (!hv)
        return 0;
 
     xhv = (XPVHV*)SvANY(hv);
     if (SvMAGICAL(hv)) {
-       dTHR;
        bool needs_copy;
        bool needs_store;
        hv_magic_check (hv, &needs_copy, &needs_store);
@@ -384,7 +545,7 @@ Perl_hv_store_ent(pTHX_ HV *hv, SV *keysv, SV *val, register U32 hash)
            if (!xhv->xhv_array && !needs_store)
                return Nullhe;
 #ifdef ENV_IS_CASELESS
-           else if (mg_find((SV*)hv,'E')) {
+           else if (mg_find((SV*)hv, PERL_MAGIC_env)) {
                key = SvPV(keysv, klen);
                keysv = sv_2mortal(newSVpvn(key,klen));
                (void)strupr(SvPVX(keysv));
@@ -394,7 +555,11 @@ Perl_hv_store_ent(pTHX_ HV *hv, SV *keysv, SV *val, register U32 hash)
        }
     }
 
-    key = SvPV(keysv, klen);
+    keysave = key = SvPV(keysv, klen);
+    is_utf8 = (SvUTF8(keysv) != 0);
+
+    if (is_utf8 && !(PL_hints & HINT_UTF8_DISTINCT))
+       key = (char*)bytes_from_utf8((U8*)key, &klen, &is_utf8);
 
     if (!hash)
        PERL_HASH(hash, key, klen);
@@ -411,18 +576,24 @@ Perl_hv_store_ent(pTHX_ HV *hv, SV *keysv, SV *val, register U32 hash)
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (memNE(HeKEY(entry),key,klen))       /* is this it? */
+       if (HeKEY(entry) != key && memNE(HeKEY(entry),key,klen))        /* is this it? */
+           continue;
+       if (HeKUTF8(entry) != (char)is_utf8)
            continue;
        SvREFCNT_dec(HeVAL(entry));
        HeVAL(entry) = val;
+       if (key != keysave)
+           Safefree(key);
        return entry;
     }
 
-    entry = new_he();
+    entry = new_HE();
     if (HvSHAREKEYS(hv))
-       HeKEY_hek(entry) = share_hek(key, klen, hash);
+       HeKEY_hek(entry) = share_hek(key, is_utf8?-klen:klen, hash);
     else                                       /* gotta do the real thing */
-       HeKEY_hek(entry) = save_hek(key, klen, hash);
+       HeKEY_hek(entry) = save_hek(key, is_utf8?-klen:klen, hash);
+    if (key != keysave)
+       Safefree(key);
     HeVAL(entry) = val;
     HeNEXT(entry) = *oentry;
     *oentry = entry;
@@ -437,8 +608,19 @@ Perl_hv_store_ent(pTHX_ HV *hv, SV *keysv, SV *val, register U32 hash)
     return entry;
 }
 
+/*
+=for apidoc hv_delete
+
+Deletes a key/value pair in the hash.  The value SV is removed from the
+hash and returned to the caller.  The C<klen> is the length of the key.
+The C<flags> value will normally be zero; if set to G_DISCARD then NULL
+will be returned.
+
+=cut
+*/
+
 SV *
-Perl_hv_delete(pTHX_ HV *hv, const char *key, U32 klen, I32 flags)
+Perl_hv_delete(pTHX_ HV *hv, const char *key, I32 klen, I32 flags)
 {
     register XPVHV* xhv;
     register I32 i;
@@ -447,9 +629,15 @@ Perl_hv_delete(pTHX_ HV *hv, const char *key, U32 klen, I32 flags)
     register HE **oentry;
     SV **svp;
     SV *sv;
+    bool is_utf8 = FALSE;
+    const char *keysave = key;
 
     if (!hv)
        return Nullsv;
+    if (klen < 0) {
+      klen = -klen;
+      is_utf8 = TRUE;
+    }
     if (SvRMAGICAL(hv)) {
        bool needs_copy;
        bool needs_store;
@@ -459,14 +647,15 @@ Perl_hv_delete(pTHX_ HV *hv, const char *key, U32 klen, I32 flags)
            sv = *svp;
            mg_clear(sv);
            if (!needs_store) {
-               if (mg_find(sv, 'p')) {
-                   sv_unmagic(sv, 'p');        /* No longer an element */
+               if (mg_find(sv, PERL_MAGIC_tiedelem)) {
+                   /* No longer an element */
+                   sv_unmagic(sv, PERL_MAGIC_tiedelem);
                    return sv;
                }
                return Nullsv;          /* element cannot be deleted */
            }
 #ifdef ENV_IS_CASELESS
-           else if (mg_find((SV*)hv,'E')) {
+           else if (mg_find((SV*)hv, PERL_MAGIC_env)) {
                sv = sv_2mortal(newSVpvn(key,klen));
                key = strupr(SvPVX(sv));
            }
@@ -477,6 +666,13 @@ Perl_hv_delete(pTHX_ HV *hv, const char *key, U32 klen, I32 flags)
     if (!xhv->xhv_array)
        return Nullsv;
 
+    if (is_utf8 && !(PL_hints & HINT_UTF8_DISTINCT)) {
+       STRLEN tmplen = klen;
+       /* See the note in hv_fetch(). --jhi */
+       key = (char*)bytes_from_utf8((U8*)key, &tmplen, &is_utf8);
+       klen = tmplen;
+    }
+
     PERL_HASH(hash, key, klen);
 
     oentry = &((HE**)xhv->xhv_array)[hash & (I32) xhv->xhv_max];
@@ -487,15 +683,21 @@ Perl_hv_delete(pTHX_ HV *hv, const char *key, U32 klen, I32 flags)
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (memNE(HeKEY(entry),key,klen))       /* is this it? */
+       if (HeKEY(entry) != key && memNE(HeKEY(entry),key,klen))        /* is this it? */
            continue;
+       if (HeKUTF8(entry) != (char)is_utf8)
+           continue;
+       if (key != keysave)
+           Safefree(key);
        *oentry = HeNEXT(entry);
        if (i && !*oentry)
            xhv->xhv_fill--;
        if (flags & G_DISCARD)
            sv = Nullsv;
-       else
-           sv = sv_mortalcopy(HeVAL(entry));
+       else {
+           sv = sv_2mortal(HeVAL(entry));
+           HeVAL(entry) = &PL_sv_undef;
+       }
        if (entry == xhv->xhv_eiter)
            HvLAZYDEL_on(hv);
        else
@@ -503,9 +705,22 @@ Perl_hv_delete(pTHX_ HV *hv, const char *key, U32 klen, I32 flags)
        --xhv->xhv_keys;
        return sv;
     }
+    if (key != keysave)
+       Safefree(key);
     return Nullsv;
 }
 
+/*
+=for apidoc hv_delete_ent
+
+Deletes a key/value pair in the hash.  The value SV is removed from the
+hash and returned to the caller.  The C<flags> value will normally be zero;
+if set to G_DISCARD then NULL will be returned.  C<hash> can be a valid
+precomputed hash value, or 0 to ask for it to be computed.
+
+=cut
+*/
+
 SV *
 Perl_hv_delete_ent(pTHX_ HV *hv, SV *keysv, I32 flags, U32 hash)
 {
@@ -516,7 +731,9 @@ Perl_hv_delete_ent(pTHX_ HV *hv, SV *keysv, I32 flags, U32 hash)
     register HE *entry;
     register HE **oentry;
     SV *sv;
-    
+    bool is_utf8;
+    char *keysave;
+
     if (!hv)
        return Nullsv;
     if (SvRMAGICAL(hv)) {
@@ -528,18 +745,19 @@ Perl_hv_delete_ent(pTHX_ HV *hv, SV *keysv, I32 flags, U32 hash)
            sv = HeVAL(entry);
            mg_clear(sv);
            if (!needs_store) {
-               if (mg_find(sv, 'p')) {
-                   sv_unmagic(sv, 'p');        /* No longer an element */
+               if (mg_find(sv, PERL_MAGIC_tiedelem)) {
+                   /* No longer an element */
+                   sv_unmagic(sv, PERL_MAGIC_tiedelem);
                    return sv;
                }               
                return Nullsv;          /* element cannot be deleted */
            }
 #ifdef ENV_IS_CASELESS
-           else if (mg_find((SV*)hv,'E')) {
+           else if (mg_find((SV*)hv, PERL_MAGIC_env)) {
                key = SvPV(keysv, klen);
                keysv = sv_2mortal(newSVpvn(key,klen));
                (void)strupr(SvPVX(keysv));
-               hash = 0; 
+               hash = 0;
            }
 #endif
        }
@@ -548,8 +766,12 @@ Perl_hv_delete_ent(pTHX_ HV *hv, SV *keysv, I32 flags, U32 hash)
     if (!xhv->xhv_array)
        return Nullsv;
 
-    key = SvPV(keysv, klen);
-    
+    keysave = key = SvPV(keysv, klen);
+    is_utf8 = (SvUTF8(keysv) != 0);
+
+    if (is_utf8 && !(PL_hints & HINT_UTF8_DISTINCT))
+       key = (char*)bytes_from_utf8((U8*)key, &klen, &is_utf8);
+
     if (!hash)
        PERL_HASH(hash, key, klen);
 
@@ -561,15 +783,21 @@ Perl_hv_delete_ent(pTHX_ HV *hv, SV *keysv, I32 flags, U32 hash)
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (memNE(HeKEY(entry),key,klen))       /* is this it? */
+       if (HeKEY(entry) != key && memNE(HeKEY(entry),key,klen))        /* is this it? */
            continue;
+       if (HeKUTF8(entry) != (char)is_utf8)
+           continue;
+       if (key != keysave)
+           Safefree(key);
        *oentry = HeNEXT(entry);
        if (i && !*oentry)
            xhv->xhv_fill--;
        if (flags & G_DISCARD)
            sv = Nullsv;
-       else
-           sv = sv_mortalcopy(HeVAL(entry));
+       else {
+           sv = sv_2mortal(HeVAL(entry));
+           HeVAL(entry) = &PL_sv_undef;
+       }
        if (entry == xhv->xhv_eiter)
            HvLAZYDEL_on(hv);
        else
@@ -577,30 +805,47 @@ Perl_hv_delete_ent(pTHX_ HV *hv, SV *keysv, I32 flags, U32 hash)
        --xhv->xhv_keys;
        return sv;
     }
+    if (key != keysave)
+       Safefree(key);
     return Nullsv;
 }
 
+/*
+=for apidoc hv_exists
+
+Returns a boolean indicating whether the specified hash key exists.  The
+C<klen> is the length of the key.
+
+=cut
+*/
+
 bool
-Perl_hv_exists(pTHX_ HV *hv, const char *key, U32 klen)
+Perl_hv_exists(pTHX_ HV *hv, const char *key, I32 klen)
 {
     register XPVHV* xhv;
     register U32 hash;
     register HE *entry;
     SV *sv;
+    bool is_utf8 = FALSE;
+    const char *keysave = key;
 
     if (!hv)
        return 0;
 
+    if (klen < 0) {
+      klen = -klen;
+      is_utf8 = TRUE;
+    }
+
     if (SvRMAGICAL(hv)) {
-       if (mg_find((SV*)hv,'P')) {
-           dTHR;
+       if (mg_find((SV*)hv, PERL_MAGIC_tied) || SvGMAGICAL((SV*)hv)) {
            sv = sv_newmortal();
-           mg_copy((SV*)hv, sv, key, klen); 
-           magic_existspack(sv, mg_find(sv, 'p'));
+           mg_copy((SV*)hv, sv, key, klen);
+           magic_existspack(sv, mg_find(sv, PERL_MAGIC_tiedelem));
            return SvTRUE(sv);
        }
 #ifdef ENV_IS_CASELESS
-       else if (mg_find((SV*)hv,'E')) {
+       else if (mg_find((SV*)hv, PERL_MAGIC_env)) {
            sv = sv_2mortal(newSVpvn(key,klen));
            key = strupr(SvPVX(sv));
        }
@@ -610,9 +855,16 @@ Perl_hv_exists(pTHX_ HV *hv, const char *key, U32 klen)
     xhv = (XPVHV*)SvANY(hv);
 #ifndef DYNAMIC_ENV_FETCH
     if (!xhv->xhv_array)
-       return 0; 
+       return 0;
 #endif
 
+    if (is_utf8 && !(PL_hints & HINT_UTF8_DISTINCT)) {
+       STRLEN tmplen = klen;
+       /* See the note in hv_fetch(). --jhi */
+       key = (char*)bytes_from_utf8((U8*)key, &tmplen, &is_utf8);
+       klen = tmplen;
+    }
+
     PERL_HASH(hash, key, klen);
 
 #ifdef DYNAMIC_ENV_FETCH
@@ -625,8 +877,12 @@ Perl_hv_exists(pTHX_ HV *hv, const char *key, U32 klen)
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (memNE(HeKEY(entry),key,klen))       /* is this it? */
+       if (HeKEY(entry) != key && memNE(HeKEY(entry),key,klen))        /* is this it? */
            continue;
+       if (HeKUTF8(entry) != (char)is_utf8)
+           continue;
+       if (key != keysave)
+           Safefree(key);
        return TRUE;
     }
 #ifdef DYNAMIC_ENV_FETCH  /* is it out there? */
@@ -641,10 +897,22 @@ Perl_hv_exists(pTHX_ HV *hv, const char *key, U32 klen)
        }
     }
 #endif
+    if (key != keysave)
+       Safefree(key);
     return FALSE;
 }
 
 
+/*
+=for apidoc hv_exists_ent
+
+Returns a boolean indicating whether the specified hash key exists. C<hash>
+can be a valid precomputed hash value, or 0 to ask for it to be
+computed.
+
+=cut
+*/
+
 bool
 Perl_hv_exists_ent(pTHX_ HV *hv, SV *keysv, U32 hash)
 {
@@ -653,25 +921,27 @@ Perl_hv_exists_ent(pTHX_ HV *hv, SV *keysv, U32 hash)
     STRLEN klen;
     register HE *entry;
     SV *sv;
+    bool is_utf8;
+    char *keysave;
 
     if (!hv)
        return 0;
 
     if (SvRMAGICAL(hv)) {
-       if (mg_find((SV*)hv,'P')) {
-           dTHR;               /* just for SvTRUE */
+       if (mg_find((SV*)hv, PERL_MAGIC_tied) || SvGMAGICAL((SV*)hv)) {
+           SV* svret = sv_newmortal();
            sv = sv_newmortal();
            keysv = sv_2mortal(newSVsv(keysv));
-           mg_copy((SV*)hv, sv, (char*)keysv, HEf_SVKEY); 
-           magic_existspack(sv, mg_find(sv, 'p'));
-           return SvTRUE(sv);
+           mg_copy((SV*)hv, sv, (char*)keysv, HEf_SVKEY);
+           magic_existspack(svret, mg_find(sv, PERL_MAGIC_tiedelem));
+           return SvTRUE(svret);
        }
 #ifdef ENV_IS_CASELESS
-       else if (mg_find((SV*)hv,'E')) {
+       else if (mg_find((SV*)hv, PERL_MAGIC_env)) {
            key = SvPV(keysv, klen);
            keysv = sv_2mortal(newSVpvn(key,klen));
            (void)strupr(SvPVX(keysv));
-           hash = 0; 
+           hash = 0;
        }
 #endif
     }
@@ -679,10 +949,13 @@ Perl_hv_exists_ent(pTHX_ HV *hv, SV *keysv, U32 hash)
     xhv = (XPVHV*)SvANY(hv);
 #ifndef DYNAMIC_ENV_FETCH
     if (!xhv->xhv_array)
-       return 0; 
+       return 0;
 #endif
 
-    key = SvPV(keysv, klen);
+    keysave = key = SvPV(keysv, klen);
+    is_utf8 = (SvUTF8(keysv) != 0);
+    if (is_utf8 && !(PL_hints & HINT_UTF8_DISTINCT))
+       key = (char*)bytes_from_utf8((U8*)key, &klen, &is_utf8);
     if (!hash)
        PERL_HASH(hash, key, klen);
 
@@ -696,8 +969,12 @@ Perl_hv_exists_ent(pTHX_ HV *hv, SV *keysv, U32 hash)
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (memNE(HeKEY(entry),key,klen))       /* is this it? */
+       if (HeKEY(entry) != key && memNE(HeKEY(entry),key,klen))        /* is this it? */
+           continue;
+       if (HeKUTF8(entry) != (char)is_utf8)
            continue;
+       if (key != keysave)
+           Safefree(key);
        return TRUE;
     }
 #ifdef DYNAMIC_ENV_FETCH  /* is it out there? */
@@ -712,6 +989,8 @@ Perl_hv_exists_ent(pTHX_ HV *hv, SV *keysv, U32 hash)
        }
     }
 #endif
+    if (key != keysave)
+       Safefree(key);
     return FALSE;
 }
 
@@ -736,7 +1015,6 @@ S_hsplit(pTHX_ HV *hv)
       return;
     }
 #else
-#define MALLOC_OVERHEAD 16
     New(2, a, PERL_HV_ARRAY_ALLOC_BYTES(newsize), char);
     if (!a) {
       PL_nomemok = FALSE;
@@ -855,6 +1133,14 @@ Perl_hv_ksplit(pTHX_ HV *hv, IV newmax)
     }
 }
 
+/*
+=for apidoc newHV
+
+Creates a new HV.  The reference count is set to 1.
+
+=cut
+*/
+
 HV *
 Perl_newHV(pTHX)
 {
@@ -866,9 +1152,9 @@ Perl_newHV(pTHX)
     xhv = (XPVHV*)SvANY(hv);
     SvPOK_off(hv);
     SvNOK_off(hv);
-#ifndef NODEFAULT_SHAREKEYS    
+#ifndef NODEFAULT_SHAREKEYS
     HvSHAREKEYS_on(hv);         /* key-sharing on by default */
-#endif    
+#endif
     xhv->xhv_max = 7;          /* start with 8 buckets */
     xhv->xhv_fill = 0;
     xhv->xhv_pmroot = 0;
@@ -891,10 +1177,10 @@ Perl_newHVhv(pTHX_ HV *ohv)
        return hv;
 
 #if 0
-    if (! SvTIED_mg((SV*)ohv, 'P')) {
+    if (! SvTIED_mg((SV*)ohv, PERL_MAGIC_tied)) {
        /* Quick way ???*/
-    } 
-    else 
+    }
+    else
 #endif
     {
        HE *entry;
@@ -903,14 +1189,14 @@ Perl_newHVhv(pTHX_ HV *ohv)
        
        /* Slow way */
        hv_iterinit(ohv);
-       while (entry = hv_iternext(ohv)) {
-           hv_store(hv, HeKEY(entry), HeKLEN(entry), 
-                    SvREFCNT_inc(HeVAL(entry)), HeHASH(entry));
+       while ((entry = hv_iternext(ohv))) {
+           hv_store(hv, HeKEY(entry), HeKLEN_UTF8(entry),
+                    newSVsv(HeVAL(entry)), HeHASH(entry));
        }
        HvRITER(ohv) = hv_riter;
        HvEITER(ohv) = hv_eiter;
     }
-    
+
     return hv;
 }
 
@@ -933,7 +1219,7 @@ Perl_hv_free_ent(pTHX_ HV *hv, register HE *entry)
        unshare_hek(HeKEY_hek(entry));
     else
        Safefree(HeKEY_hek(entry));
-    del_he(entry);
+    del_HE(entry);
 }
 
 void
@@ -952,9 +1238,17 @@ Perl_hv_delayfree_ent(pTHX_ HV *hv, register HE *entry)
        unshare_hek(HeKEY_hek(entry));
     else
        Safefree(HeKEY_hek(entry));
-    del_he(entry);
+    del_HE(entry);
 }
 
+/*
+=for apidoc hv_clear
+
+Clears a hash, making it empty.
+
+=cut
+*/
+
 void
 Perl_hv_clear(pTHX_ HV *hv)
 {
@@ -969,7 +1263,7 @@ Perl_hv_clear(pTHX_ HV *hv)
        (void)memzero(xhv->xhv_array, (xhv->xhv_max + 1) * sizeof(HE*));
 
     if (SvRMAGICAL(hv))
-       mg_clear((SV*)hv); 
+       mg_clear((SV*)hv);
 }
 
 STATIC void
@@ -1000,11 +1294,19 @@ S_hfreeentries(pTHX_ HV *hv)
            if (++riter > max)
                break;
            entry = array[riter];
-       } 
+       }
     }
     (void)hv_iterinit(hv);
 }
 
+/*
+=for apidoc hv_undef
+
+Undefines the hash.
+
+=cut
+*/
+
 void
 Perl_hv_undef(pTHX_ HV *hv)
 {
@@ -1024,9 +1326,23 @@ Perl_hv_undef(pTHX_ HV *hv)
     xhv->xhv_keys = 0;
 
     if (SvRMAGICAL(hv))
-       mg_clear((SV*)hv); 
+       mg_clear((SV*)hv);
 }
 
+/*
+=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<HvKEYS(tb)>).  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
+value, you can get it through the macro C<HvFILL(tb)>.
+
+=cut
+*/
+
 I32
 Perl_hv_iterinit(pTHX_ HV *hv)
 {
@@ -1046,6 +1362,14 @@ Perl_hv_iterinit(pTHX_ HV *hv)
     return xhv->xhv_keys;      /* used to be xhv->xhv_fill before 5.004_65 */
 }
 
+/*
+=for apidoc hv_iternext
+
+Returns entries from a hash iterator.  See C<hv_iterinit>.
+
+=cut
+*/
+
 HE *
 Perl_hv_iternext(pTHX_ HV *hv)
 {
@@ -1059,7 +1383,7 @@ Perl_hv_iternext(pTHX_ HV *hv)
     xhv = (XPVHV*)SvANY(hv);
     oldentry = entry = xhv->xhv_eiter;
 
-    if (mg = SvTIED_mg((SV*)hv, 'P')) {
+    if ((mg = SvTIED_mg((SV*)hv, PERL_MAGIC_tied))) {
        SV *key = sv_newmortal();
        if (entry) {
            sv_setsv(key, HeSVKEY_force(entry));
@@ -1069,7 +1393,7 @@ Perl_hv_iternext(pTHX_ HV *hv)
            char *k;
            HEK *hek;
 
-           xhv->xhv_eiter = entry = new_he();  /* one HE per MAGICAL hash */
+           xhv->xhv_eiter = entry = new_HE();  /* one HE per MAGICAL hash */
            Zero(entry, 1, HE);
            Newz(54, k, HEK_BASESIZE + sizeof(SV*), char);
            hek = (HEK*)k;
@@ -1085,7 +1409,7 @@ Perl_hv_iternext(pTHX_ HV *hv)
        if (HeVAL(entry))
            SvREFCNT_dec(HeVAL(entry));
        Safefree(HeKEY_hek(entry));
-       del_he(entry);
+       del_HE(entry);
        xhv->xhv_eiter = Null(HE*);
        return Null(HE*);
     }
@@ -1117,6 +1441,15 @@ Perl_hv_iternext(pTHX_ HV *hv)
     return entry;
 }
 
+/*
+=for apidoc hv_iterkey
+
+Returns the key from the current position of the hash iterator.  See
+C<hv_iterinit>.
+
+=cut
+*/
+
 char *
 Perl_hv_iterkey(pTHX_ register HE *entry, I32 *retlen)
 {
@@ -1133,21 +1466,40 @@ Perl_hv_iterkey(pTHX_ register HE *entry, I32 *retlen)
 }
 
 /* unlike hv_iterval(), this always returns a mortal copy of the key */
+/*
+=for apidoc hv_iterkeysv
+
+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>.
+
+=cut
+*/
+
 SV *
 Perl_hv_iterkeysv(pTHX_ register HE *entry)
 {
     if (HeKLEN(entry) == HEf_SVKEY)
        return sv_mortalcopy(HeKEY_sv(entry));
     else
-       return sv_2mortal(newSVpvn((HeKLEN(entry) ? HeKEY(entry) : ""),
-                                 HeKLEN(entry)));
+       return sv_2mortal(newSVpvn_share((HeKLEN(entry) ? HeKEY(entry) : ""),
+                                        HeKLEN_UTF8(entry), HeHASH(entry)));
 }
 
+/*
+=for apidoc hv_iterval
+
+Returns the value from the current position of the hash iterator.  See
+C<hv_iterkey>.
+
+=cut
+*/
+
 SV *
 Perl_hv_iterval(pTHX_ HV *hv, register HE *entry)
 {
     if (SvRMAGICAL(hv)) {
-       if (mg_find((SV*)hv,'P')) {
+       if (mg_find((SV*)hv, PERL_MAGIC_tied)) {
            SV* sv = sv_newmortal();
            if (HeKLEN(entry) == HEf_SVKEY)
                mg_copy((SV*)hv, sv, (char*)HeKEY_sv(entry), HEf_SVKEY);
@@ -1158,6 +1510,15 @@ Perl_hv_iterval(pTHX_ HV *hv, register HE *entry)
     return HeVAL(entry);
 }
 
+/*
+=for apidoc hv_iternextsv
+
+Performs an C<hv_iternext>, C<hv_iterkey>, and C<hv_iterval> in one
+operation.
+
+=cut
+*/
+
 SV *
 Perl_hv_iternextsv(pTHX_ HV *hv, char **key, I32 *retlen)
 {
@@ -1168,6 +1529,14 @@ Perl_hv_iternextsv(pTHX_ HV *hv, char **key, I32 *retlen)
     return hv_iterval(hv, he);
 }
 
+/*
+=for apidoc hv_magic
+
+Adds magic to a hash.  See C<sv_magic>.
+
+=cut
+*/
+
 void
 Perl_hv_magic(pTHX_ HV *hv, GV *gv, int how)
 {
@@ -1191,7 +1560,20 @@ Perl_unsharepvn(pTHX_ const char *str, I32 len, U32 hash)
     register HE **oentry;
     register I32 i = 1;
     I32 found = 0;
-    
+    bool is_utf8 = FALSE;
+    const char *save = str;
+
+    if (len < 0) {
+      len = -len;
+      is_utf8 = TRUE;
+      if (!(PL_hints & HINT_UTF8_DISTINCT)) {
+         STRLEN tmplen = len;
+         /* See the note in hv_fetch(). --jhi */
+         str = (char*)bytes_from_utf8((U8*)str, &tmplen, &is_utf8);
+         len = tmplen;
+      }
+    }
+
     /* what follows is the moral equivalent of:
     if ((Svp = hv_fetch(PL_strtab, tmpsv, FALSE, hash))) {
        if (--*Svp == Nullsv)
@@ -1206,7 +1588,9 @@ Perl_unsharepvn(pTHX_ const char *str, I32 len, U32 hash)
            continue;
        if (HeKLEN(entry) != len)
            continue;
-       if (memNE(HeKEY(entry),str,len))        /* is this it? */
+       if (HeKEY(entry) != str && memNE(HeKEY(entry),str,len)) /* is this it? */
+           continue;
+       if (HeKUTF8(entry) != (char)is_utf8)
            continue;
        found = 1;
        if (--HeVAL(entry) == Nullsv) {
@@ -1214,18 +1598,16 @@ Perl_unsharepvn(pTHX_ const char *str, I32 len, U32 hash)
            if (i && !*oentry)
                xhv->xhv_fill--;
            Safefree(HeKEY_hek(entry));
-           del_he(entry);
+           del_HE(entry);
            --xhv->xhv_keys;
        }
        break;
     }
     UNLOCK_STRTAB_MUTEX;
-    
-    {
-        dTHR;
-        if (!found && ckWARN_d(WARN_INTERNAL))
-           Perl_warner(aTHX_ WARN_INTERNAL, "Attempt to free non-existent shared string");    
-    }
+    if (str != save)
+       Safefree(str);
+    if (!found && ckWARN_d(WARN_INTERNAL))
+       Perl_warner(aTHX_ WARN_INTERNAL, "Attempt to free non-existent shared string '%s'",str);
 }
 
 /* get a (constant) string ptr from the global string table
@@ -1240,9 +1622,22 @@ Perl_share_hek(pTHX_ const char *str, I32 len, register U32 hash)
     register HE **oentry;
     register I32 i = 1;
     I32 found = 0;
+    bool is_utf8 = FALSE;
+    const char *save = str;
+
+    if (len < 0) {
+      len = -len;
+      is_utf8 = TRUE;
+      if (!(PL_hints & HINT_UTF8_DISTINCT)) {
+         STRLEN tmplen = len;
+         /* See the note in hv_fetch(). --jhi */
+         str = (char*)bytes_from_utf8((U8*)str, &tmplen, &is_utf8);
+         len = tmplen;
+      }
+    }
 
     /* what follows is the moral equivalent of:
-       
+
     if (!(Svp = hv_fetch(PL_strtab, str, len, FALSE)))
        hv_store(PL_strtab, str, len, Nullsv, hash);
     */
@@ -1255,14 +1650,16 @@ Perl_share_hek(pTHX_ const char *str, I32 len, register U32 hash)
            continue;
        if (HeKLEN(entry) != len)
            continue;
-       if (memNE(HeKEY(entry),str,len))        /* is this it? */
+       if (HeKEY(entry) != str && memNE(HeKEY(entry),str,len)) /* is this it? */
+           continue;
+       if (HeKUTF8(entry) != (char)is_utf8)
            continue;
        found = 1;
        break;
     }
     if (!found) {
-       entry = new_he();
-       HeKEY_hek(entry) = save_hek(str, len, hash);
+       entry = new_HE();
+       HeKEY_hek(entry) = save_hek(str, is_utf8?-len:len, hash);
        HeVAL(entry) = Nullsv;
        HeNEXT(entry) = *oentry;
        *oentry = entry;
@@ -1276,8 +1673,7 @@ Perl_share_hek(pTHX_ const char *str, I32 len, register U32 hash)
 
     ++HeVAL(entry);                            /* use value slot as REFCNT */
     UNLOCK_STRTAB_MUTEX;
+    if (str != save)
+       Safefree(str);
     return HeKEY_hek(entry);
 }
-
-
-