[inseparable changes from patch from perl5.003_20 to perl5.003_21]
[p5sagit/p5-mst-13.2.git] / hv.c
diff --git a/hv.c b/hv.c
index a2ddf7b..71009c9 100644 (file)
--- a/hv.c
+++ b/hv.c
@@ -55,6 +55,31 @@ more_he()
     return new_he();
 }
 
+static HEK *
+save_hek(str, len, hash)
+char *str;
+I32 len;
+U32 hash;
+{
+    char *k;
+    register HEK *hek;
+    
+    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;
+    return hek;
+}
+
+void
+unshare_hek(hek)
+HEK *hek;
+{
+    unsharepvn(HEK_KEY(hek),HEK_LEN(hek),HEK_HASH(hek));
+}
+
 /* (klen == HEf_SVKEY) is special for MAGICAL hv entries, meaning key slot
  * contains an SV* */
 
@@ -102,7 +127,7 @@ I32 lval;
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (bcmp(HeKEY(entry),key,klen))        /* is this it? */
+       if (memNE(HeKEY(entry),key,klen))       /* is this it? */
            continue;
        return &HeVAL(entry);
     }
@@ -142,28 +167,24 @@ register U32 hash;
     if (!hv)
        return 0;
 
-    xhv = (XPVHV*)SvANY(hv);
-
     if (SvRMAGICAL(hv) && mg_find((SV*)hv,'P')) {
-       if (!(entry = xhv->xhv_eiter)) {
-           xhv->xhv_eiter = entry = new_he();  /* only one HE per MAGICAL hash */
-           Zero(entry, 1, HE);
-           HeKLEN(entry) = HEf_SVKEY;          /* hent_key is holding an SV* */
-       }
-       else if ((sv = HeSVKEY(entry)))
-           SvREFCNT_dec(sv);
+       static HE mh;
+
        sv = sv_newmortal();
+       keysv = sv_2mortal(newSVsv(keysv));
        mg_copy((SV*)hv, sv, (char*)keysv, HEf_SVKEY);
-       HeVAL(entry) = sv;
-       HeKEY(entry) = (char*)SvREFCNT_inc(keysv);
-       return entry;
+       if (!HeKEY_hek(&mh)) {
+           char *k;
+           New(54, k, HEK_BASESIZE + sizeof(SV*), char);
+           HeKEY_hek(&mh) = (HEK*)k;
+           HeKLEN(&mh) = HEf_SVKEY;    /* key will always hold an SV* */
+       }
+       HeSVKEY_set(&mh, keysv);
+       HeVAL(&mh) = sv;
+       return &mh;
     }
 
-    key = SvPV(keysv, klen);
-    
-    if (!hash)
-       PERL_HASH(hash, key, klen);
-
+    xhv = (XPVHV*)SvANY(hv);
     if (!xhv->xhv_array) {
        if (lval 
 #ifdef DYNAMIC_ENV_FETCH  /* if it's an %ENV lookup, we may get it on the fly */
@@ -175,13 +196,18 @@ register U32 hash;
            return 0;
     }
 
+    key = SvPV(keysv, klen);
+    
+    if (!hash)
+       PERL_HASH(hash, key, klen);
+
     entry = ((HE**)xhv->xhv_array)[hash & (I32) xhv->xhv_max];
     for (; entry; entry = HeNEXT(entry)) {
        if (HeHASH(entry) != hash)              /* strings can't be equal */
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (bcmp(HeKEY(entry),key,klen))        /* is this it? */
+       if (memNE(HeKEY(entry),key,klen))       /* is this it? */
            continue;
        return entry;
     }
@@ -222,14 +248,14 @@ register U32 hash;
     xhv = (XPVHV*)SvANY(hv);
     if (SvMAGICAL(hv)) {
        mg_copy((SV*)hv, val, key, klen);
-#ifndef OVERLOAD
-       if (!xhv->xhv_array)
-           return 0;
-#else
-       if (!xhv->xhv_array && (SvMAGIC(hv)->mg_type != 'A'
-                               || SvMAGIC(hv)->mg_moremagic))
-         return 0;
+       if (!xhv->xhv_array
+           && (SvMAGIC(hv)->mg_moremagic
+               || (SvMAGIC(hv)->mg_type != 'E'
+#ifdef OVERLOAD
+                   && SvMAGIC(hv)->mg_type != 'A'
 #endif /* OVERLOAD */
+                   )))
+           return 0;
     }
     if (!hash)
        PERL_HASH(hash, key, klen);
@@ -245,7 +271,7 @@ register U32 hash;
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (bcmp(HeKEY(entry),key,klen))        /* is this it? */
+       if (memNE(HeKEY(entry),key,klen))       /* is this it? */
            continue;
        SvREFCNT_dec(HeVAL(entry));
        HeVAL(entry) = val;
@@ -253,13 +279,11 @@ register U32 hash;
     }
 
     entry = new_he();
-    HeKLEN(entry) = klen;
     if (HvSHAREKEYS(hv))
-       HeKEY(entry) = sharepvn(key, klen, hash);
+       HeKEY_hek(entry) = share_hek(key, klen, hash);
     else                                       /* gotta do the real thing */
-       HeKEY(entry) = savepvn(key,klen);
+       HeKEY_hek(entry) = save_hek(key, klen, hash);
     HeVAL(entry) = val;
-    HeHASH(entry) = hash;
     HeNEXT(entry) = *oentry;
     *oentry = entry;
 
@@ -292,15 +316,16 @@ register U32 hash;
 
     xhv = (XPVHV*)SvANY(hv);
     if (SvMAGICAL(hv)) {
+       keysv = sv_2mortal(newSVsv(keysv));
        mg_copy((SV*)hv, val, (char*)keysv, HEf_SVKEY);
-#ifndef OVERLOAD
-       if (!xhv->xhv_array)
-           return Nullhe;
-#else
-       if (!xhv->xhv_array && (SvMAGIC(hv)->mg_type != 'A'
-                               || SvMAGIC(hv)->mg_moremagic))
-         return Nullhe;
+       if (!xhv->xhv_array
+           && (SvMAGIC(hv)->mg_moremagic
+               || (SvMAGIC(hv)->mg_type != 'E'
+#ifdef OVERLOAD
+                   && SvMAGIC(hv)->mg_type != 'A'
 #endif /* OVERLOAD */
+                   )))
+         return Nullhe;
     }
 
     key = SvPV(keysv, klen);
@@ -319,7 +344,7 @@ register U32 hash;
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (bcmp(HeKEY(entry),key,klen))        /* is this it? */
+       if (memNE(HeKEY(entry),key,klen))       /* is this it? */
            continue;
        SvREFCNT_dec(HeVAL(entry));
        HeVAL(entry) = val;
@@ -327,13 +352,11 @@ register U32 hash;
     }
 
     entry = new_he();
-    HeKLEN(entry) = klen;
     if (HvSHAREKEYS(hv))
-       HeKEY(entry) = sharepvn(key, klen, hash);
+       HeKEY_hek(entry) = share_hek(key, klen, hash);
     else                                       /* gotta do the real thing */
-       HeKEY(entry) = savepvn(key,klen);
+       HeKEY_hek(entry) = save_hek(key, klen, hash);
     HeVAL(entry) = val;
-    HeHASH(entry) = hash;
     HeNEXT(entry) = *oentry;
     *oentry = entry;
 
@@ -388,7 +411,7 @@ I32 flags;
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (bcmp(HeKEY(entry),key,klen))        /* is this it? */
+       if (memNE(HeKEY(entry),key,klen))       /* is this it? */
            continue;
        *oentry = HeNEXT(entry);
        if (i && !*oentry)
@@ -398,9 +421,9 @@ I32 flags;
        else
            sv = sv_mortalcopy(HeVAL(entry));
        if (entry == xhv->xhv_eiter)
-           HeKLEN(entry) = HEf_LAZYDEL;
+           HvLAZYDEL_on(hv);
        else
-           he_free(entry, HvSHAREKEYS(hv));
+           he_free(hv, entry);
        --xhv->xhv_keys;
        return sv;
     }
@@ -450,7 +473,7 @@ U32 hash;
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (bcmp(HeKEY(entry),key,klen))        /* is this it? */
+       if (memNE(HeKEY(entry),key,klen))       /* is this it? */
            continue;
        *oentry = HeNEXT(entry);
        if (i && !*oentry)
@@ -460,9 +483,9 @@ U32 hash;
        else
            sv = sv_mortalcopy(HeVAL(entry));
        if (entry == xhv->xhv_eiter)
-           HeKLEN(entry) = HEf_LAZYDEL;
+           HvLAZYDEL_on(hv);
        else
-           he_free(entry, HvSHAREKEYS(hv));
+           he_free(hv, entry);
        --xhv->xhv_keys;
        return sv;
     }
@@ -504,7 +527,7 @@ U32 klen;
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (bcmp(HeKEY(entry),key,klen))        /* is this it? */
+       if (memNE(HeKEY(entry),key,klen))       /* is this it? */
            continue;
        return TRUE;
     }
@@ -530,6 +553,7 @@ U32 hash;
     if (SvRMAGICAL(hv)) {
        if (mg_find((SV*)hv,'P')) {
            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);
@@ -550,7 +574,7 @@ U32 hash;
            continue;
        if (HeKLEN(entry) != klen)
            continue;
-       if (bcmp(HeKEY(entry),key,klen))        /* is this it? */
+       if (memNE(HeKEY(entry),key,klen))       /* is this it? */
            continue;
        return TRUE;
     }
@@ -622,6 +646,84 @@ HV *hv;
     }
 }
 
+void
+hv_ksplit(hv, newmax)
+HV *hv;
+IV newmax;
+{
+    register XPVHV* xhv = (XPVHV*)SvANY(hv);
+    I32 oldsize = (I32) xhv->xhv_max + 1; /* sic(k) */
+    register I32 newsize;
+    register I32 i;
+    register I32 j;
+    register HE **a;
+    register HE *entry;
+    register HE **oentry;
+
+    newsize = (I32) newmax;                    /* possible truncation here */
+    if (newsize != newmax || newmax <= oldsize)
+       return;
+    while ((newsize & (1 + ~newsize)) != newsize) {
+       newsize &= ~(newsize & (1 + ~newsize)); /* get proper power of 2 */
+    }
+    if (newsize < newmax)
+       newsize *= 2;
+    if (newsize < newmax)
+       return;                                 /* overflow detection */
+
+    a = (HE**)xhv->xhv_array;
+    if (a) {
+       nomemok = TRUE;
+#ifdef STRANGE_MALLOC
+       Renew(a, newsize, HE*);
+#else
+       i = newsize * sizeof(HE*);
+       j = MALLOC_OVERHEAD;
+       while (j - MALLOC_OVERHEAD < i)
+           j += j;
+       j -= MALLOC_OVERHEAD;
+       j /= sizeof(HE*);
+       assert(j >= newsize);
+       New(2, a, j, HE*);
+       Copy(xhv->xhv_array, a, oldsize, HE*);
+       if (oldsize >= 64 && !nice_chunk) {
+           nice_chunk = (char*)xhv->xhv_array;
+           nice_chunk_size = oldsize * sizeof(HE*) * 2 - MALLOC_OVERHEAD;
+       }
+       else
+           Safefree(xhv->xhv_array);
+#endif
+       nomemok = FALSE;
+       Zero(&a[oldsize], newsize-oldsize, HE*); /* zero 2nd half*/
+    }
+    else {
+       Newz(0, a, newsize, HE*);
+    }
+    xhv->xhv_max = --newsize;
+    xhv->xhv_array = (char*)a;
+    if (!xhv->xhv_fill)                                /* skip rest if no entries */
+       return;
+
+    for (i=0; i<oldsize; i++,a++) {
+       if (!*a)                                /* non-existent */
+           continue;
+       for (oentry = a, entry = *a; entry; entry = *oentry) {
+           if ((j = (HeHASH(entry) & newsize)) != i) {
+               j -= i;
+               *oentry = HeNEXT(entry);
+               if (!(HeNEXT(entry) = a[j]))
+                   xhv->xhv_fill++;
+               a[j] = entry;
+               continue;
+           }
+           else
+               oentry = &HeNEXT(entry);
+       }
+       if (!*a)                                /* everything moved */
+           xhv->xhv_fill--;
+    }
+}
+
 HV *
 newHV()
 {
@@ -644,36 +746,44 @@ newHV()
 }
 
 void
-he_free(hent, shared)
+he_free(hv, hent)
+HV *hv;
 register HE *hent;
-I32 shared;
 {
     if (!hent)
        return;
+    if (isGV(HeVAL(hent)) && GvCVu(HeVAL(hent)) && HvNAME(hv))
+       sub_generation++;       /* may be deletion of method from stash */
     SvREFCNT_dec(HeVAL(hent));
-    if (HeKLEN(hent) == HEf_SVKEY)
-       SvREFCNT_dec((SV*)HeKEY(hent));
-    else if (shared)
-       unsharepvn(HeKEY(hent), HeKLEN(hent), HeHASH(hent));
+    if (HeKLEN(hent) == HEf_SVKEY) {
+       SvREFCNT_dec(HeKEY_sv(hent));
+        Safefree(HeKEY_hek(hent));
+    }
+    else if (HvSHAREKEYS(hv))
+       unshare_hek(HeKEY_hek(hent));
     else
-       Safefree(HeKEY(hent));
+       Safefree(HeKEY_hek(hent));
     del_he(hent);
 }
 
 void
-he_delayfree(hent, shared)
+he_delayfree(hv, hent)
+HV *hv;
 register HE *hent;
-I32 shared;
 {
     if (!hent)
        return;
+    if (isGV(HeVAL(hent)) && GvCVu(HeVAL(hent)) && HvNAME(hv))
+       sub_generation++;       /* may be deletion of method from stash */
     sv_2mortal(HeVAL(hent));   /* free between statements */
-    if (HeKLEN(hent) == HEf_SVKEY)
-       sv_2mortal((SV*)HeKEY(hent));
-    else if (shared)
-       unsharepvn(HeKEY(hent), HeKLEN(hent), HeHASH(hent));
+    if (HeKLEN(hent) == HEf_SVKEY) {
+       sv_2mortal(HeKEY_sv(hent));
+       Safefree(HeKEY_hek(hent));
+    }
+    else if (HvSHAREKEYS(hv))
+       unshare_hek(HeKEY_hek(hent));
     else
-       Safefree(HeKEY(hent));
+       Safefree(HeKEY_hek(hent));
     del_he(hent);
 }
 
@@ -704,7 +814,6 @@ HV *hv;
     register HE *ohent = Null(HE*);
     I32 riter;
     I32 max;
-    I32 shared;
 
     if (!hv)
        return;
@@ -715,12 +824,11 @@ HV *hv;
     max = HvMAX(hv);
     array = HvARRAY(hv);
     hent = array[0];
-    shared = HvSHAREKEYS(hv);
     for (;;) {
        if (hent) {
            ohent = hent;
            hent = HeNEXT(hent);
-           he_free(ohent, shared);
+           he_free(hv, ohent);
        }
        if (!hent) {
            if (++riter > max)
@@ -760,8 +868,13 @@ HV *hv;
 {
     register XPVHV* xhv = (XPVHV*)SvANY(hv);
     HE *entry = xhv->xhv_eiter;
-    if (entry && HeKLEN(entry) == HEf_LAZYDEL) /* was deleted earlier? */
-       he_free(entry, HvSHAREKEYS(hv));
+#ifdef DYNAMIC_ENV_FETCH  /* set up %ENV for iteration */
+    if (HvNAME(hv) && strEQ(HvNAME(hv),ENV_HV_NAME)) prime_env_iter();
+#endif
+    if (entry && HvLAZYDEL(hv)) {      /* was deleted earlier? */
+       HvLAZYDEL_off(hv);
+       he_free(hv, entry);
+    }
     xhv->xhv_riter = -1;
     xhv->xhv_eiter = Null(HE*);
     return xhv->xhv_fill;
@@ -783,21 +896,30 @@ HV *hv;
 
     if (SvRMAGICAL(hv) && (mg = mg_find((SV*)hv,'P'))) {
        SV *key = sv_newmortal();
-       if (entry)
+       if (entry) {
            sv_setsv(key, HeSVKEY_force(entry));
+           SvREFCNT_dec(HeSVKEY(entry));       /* get rid of previous key */
+       }
        else {
-           xhv->xhv_eiter = entry = new_he();   /* only one HE per MAGICAL hash */
+           char *k;
+           HEK *hek;
+
+           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;
+           HeKEY_hek(entry) = hek;
            HeKLEN(entry) = HEf_SVKEY;
        }
        magic_nextpack((SV*) hv,mg,key);
         if (SvOK(key)) {
-           SvREFCNT_dec(HeSVKEY(entry));
-           HeKEY(entry) = (char*)SvREFCNT_inc(key);
-           return entry;                       /* beware, hent_val is not set */
+           /* force key to stay around until next time */
+           HeSVKEY_set(entry, SvREFCNT_inc(key));
+           return entry;               /* beware, hent_val is not set */
         }
        if (HeVAL(entry))
            SvREFCNT_dec(HeVAL(entry));
+       Safefree(HeKEY_hek(entry));
        del_he(entry);
        xhv->xhv_eiter = Null(HE*);
        return Null(HE*);
@@ -816,8 +938,10 @@ HV *hv;
        entry = ((HE**)xhv->xhv_array)[xhv->xhv_riter];
     }
 
-    if (oldentry && HeKLEN(oldentry) == HEf_LAZYDEL)   /* was deleted earlier? */
-       he_free(oldentry, HvSHAREKEYS(hv));
+    if (oldentry && HvLAZYDEL(hv)) {           /* was deleted earlier? */
+       HvLAZYDEL_off(hv);
+       he_free(hv, oldentry);
+    }
 
     xhv->xhv_eiter = entry;
     return entry;
@@ -829,7 +953,7 @@ register HE *entry;
 I32 *retlen;
 {
     if (HeKLEN(entry) == HEf_SVKEY) {
-       return SvPV((SV*)HeKEY(entry), *(STRLEN*)retlen);
+       return SvPV(HeKEY_sv(entry), *(STRLEN*)retlen);
     }
     else {
        *retlen = HeKLEN(entry);
@@ -843,7 +967,7 @@ hv_iterkeysv(entry)
 register HE *entry;
 {
     if (HeKLEN(entry) == HEf_SVKEY)
-       return sv_mortalcopy((SV*)HeKEY(entry));
+       return sv_mortalcopy(HeKEY_sv(entry));
     else
        return sv_2mortal(newSVpv((HeKLEN(entry) ? HeKEY(entry) : ""),
                                  HeKLEN(entry)));
@@ -857,7 +981,9 @@ register HE *entry;
     if (SvRMAGICAL(hv)) {
        if (mg_find((SV*)hv,'P')) {
            SV* sv = sv_newmortal();
-           mg_copy((SV*)hv, sv, HeKEY(entry), HeKLEN(entry));
+           if (HeKLEN(entry) == HEf_SVKEY)
+               mg_copy((SV*)hv, sv, (char*)HeKEY_sv(entry), HEf_SVKEY);
+           else mg_copy((SV*)hv, sv, HeKEY(entry), HeKLEN(entry));
            return sv;
        }
     }
@@ -886,65 +1012,67 @@ int how;
     sv_magic((SV*)hv, (SV*)gv, how, Nullch, 0);
 }
 
-/* get a (constant) string ptr from the global string table
- * string will get added if it is not already there.
+char*  
+sharepvn(sv, len, hash)
+char* sv;
+I32 len;
+U32 hash;
+{
+    return HEK_KEY(share_hek(sv, len, hash));
+}
+
+/* possibly free a shared string if no one has access to it
  * len and hash must both be valid for str.
  */
-char *
-sharepvn(str, len, hash)
-char *str;
+void
+unsharepvn(str, len, hash)
+char* str;
 I32 len;
-register U32 hash;
+U32 hash;
 {
     register XPVHV* xhv;
     register HE *entry;
     register HE **oentry;
     register I32 i = 1;
     I32 found = 0;
-
+    
     /* what follows is the moral equivalent of:
-       
-    if (!(Svp = hv_fetch(strtab, str, len, FALSE)))
-       hv_store(strtab, str, len, Nullsv, hash);
-    */
+    if ((Svp = hv_fetch(strtab, tmpsv, FALSE, hash))) {
+       if (--*Svp == Nullsv)
+           hv_delete(strtab, str, len, G_DISCARD, hash);
+    } */
     xhv = (XPVHV*)SvANY(strtab);
     /* assert(xhv_array != 0) */
     oentry = &((HE**)xhv->xhv_array)[hash & (I32) xhv->xhv_max];
-    for (entry = *oentry; entry; i=0, entry = HeNEXT(entry)) {
+    for (entry = *oentry; entry; i=0, oentry = &HeNEXT(entry), entry = *oentry) {
        if (HeHASH(entry) != hash)              /* strings can't be equal */
            continue;
        if (HeKLEN(entry) != len)
            continue;
-       if (bcmp(HeKEY(entry),str,len))         /* is this it? */
+       if (memNE(HeKEY(entry),str,len))        /* is this it? */
            continue;
        found = 1;
-       break;
-    }
-    if (!found) {
-       entry = new_he();
-       HeKLEN(entry) = len;
-       HeKEY(entry) = savepvn(str,len);
-       HeVAL(entry) = Nullsv;
-       HeHASH(entry) = hash;
-       HeNEXT(entry) = *oentry;
-       *oentry = entry;
-       xhv->xhv_keys++;
-       if (i) {                                /* initial entry? */
-           ++xhv->xhv_fill;
-           if (xhv->xhv_keys > xhv->xhv_max)
-               hsplit(strtab);
+       if (--HeVAL(entry) == Nullsv) {
+           *oentry = HeNEXT(entry);
+           if (i && !*oentry)
+               xhv->xhv_fill--;
+           Safefree(HeKEY_hek(entry));
+           del_he(entry);
+           --xhv->xhv_keys;
        }
+       break;
     }
-
-    ++HeVAL(entry);                            /* use value slot as REFCNT */
-    return HeKEY(entry);
+    
+    if (!found)
+       warn("Attempt to free non-existent shared string");    
 }
 
-/* possibly free a shared string if no one has access to it
+/* get a (constant) string ptr from the global string table
+ * string will get added if it is not already there.
  * len and hash must both be valid for str.
  */
-void
-unsharepvn(str, len, hash)
+HEK *
+share_hek(str, len, hash)
 char *str;
 I32 len;
 register U32 hash;
@@ -954,35 +1082,41 @@ register U32 hash;
     register HE **oentry;
     register I32 i = 1;
     I32 found = 0;
-    
+
     /* what follows is the moral equivalent of:
-    if ((Svp = hv_fetch(strtab, tmpsv, FALSE, hash))) {
-       if (--*Svp == Nullsv)
-           hv_delete(strtab, str, len, G_DISCARD, hash);
-    } */
+       
+    if (!(Svp = hv_fetch(strtab, str, len, FALSE)))
+       hv_store(strtab, str, len, Nullsv, hash);
+    */
     xhv = (XPVHV*)SvANY(strtab);
     /* assert(xhv_array != 0) */
     oentry = &((HE**)xhv->xhv_array)[hash & (I32) xhv->xhv_max];
-    for (entry = *oentry; entry; i=0, oentry = &HeNEXT(entry), entry = *oentry) {
+    for (entry = *oentry; entry; i=0, entry = HeNEXT(entry)) {
        if (HeHASH(entry) != hash)              /* strings can't be equal */
            continue;
        if (HeKLEN(entry) != len)
            continue;
-       if (bcmp(HeKEY(entry),str,len))         /* is this it? */
+       if (memNE(HeKEY(entry),str,len))        /* is this it? */
            continue;
        found = 1;
-       if (--HeVAL(entry) == Nullsv) {
-           *oentry = HeNEXT(entry);
-           if (i && !*oentry)
-               xhv->xhv_fill--;
-           Safefree(HeKEY(entry));
-           del_he(entry);
-           --xhv->xhv_keys;
-       }
        break;
     }
-    
-    if (!found)
-       warn("Attempt to free non-existent shared string");    
+    if (!found) {
+       entry = new_he();
+       HeKEY_hek(entry) = save_hek(str, len, hash);
+       HeVAL(entry) = Nullsv;
+       HeNEXT(entry) = *oentry;
+       *oentry = entry;
+       xhv->xhv_keys++;
+       if (i) {                                /* initial entry? */
+           ++xhv->xhv_fill;
+           if (xhv->xhv_keys > xhv->xhv_max)
+               hsplit(strtab);
+       }
+    }
+
+    ++HeVAL(entry);                            /* use value slot as REFCNT */
+    return HeKEY_hek(entry);
 }
 
+