X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=hv.c;h=5086b83a92f9c04cea0bdf5bd40c740caf10a2e5;hb=c4a9c09d5b30a93b6241aff3c9915e33e4e41eeb;hp=cafad726dc5e1809254e0b2fbef6bbc410d4db0d;hpb=a3b680e6b77dd7f88268fad8b1dbdf4f641dd836;p=p5sagit%2Fp5-mst-13.2.git diff --git a/hv.c b/hv.c index cafad72..5086b83 100644 --- a/hv.c +++ b/hv.c @@ -123,6 +123,23 @@ Perl_free_tied_hv_pool(pTHX) } #if defined(USE_ITHREADS) +HEK * +Perl_hek_dup(pTHX_ HEK *source, CLONE_PARAMS* param) +{ + HE *shared = (HE*)ptr_table_fetch(PL_shared_hek_table, source); + + if (shared) { + /* We already shared this hash key. */ + ++HeVAL(shared); + } + else { + shared = share_hek_flags(HEK_KEY(source), HEK_LEN(source), + HEK_HASH(source), HEK_FLAGS(source)); + ptr_table_store(PL_shared_hek_table, source, shared); + } + return HeKEY_hek(shared); +} + HE * Perl_he_dup(pTHX_ HE *e, bool shared, CLONE_PARAMS* param) { @@ -146,9 +163,23 @@ Perl_he_dup(pTHX_ HE *e, bool shared, CLONE_PARAMS* param) HeKEY_hek(ret) = (HEK*)k; HeKEY_sv(ret) = SvREFCNT_inc(sv_dup(HeKEY_sv(e), param)); } - else if (shared) - HeKEY_hek(ret) = share_hek_flags(HeKEY(e), HeKLEN(e), HeHASH(e), - HeKFLAGS(e)); + else if (shared) { + /* This is hek_dup inlined, which seems to be important for speed + reasons. */ + HEK *source = HeKEY_hek(e); + HE *shared = (HE*)ptr_table_fetch(PL_shared_hek_table, source); + + if (shared) { + /* We already shared this hash key. */ + ++HeVAL(shared); + } + else { + shared = share_hek_flags(HEK_KEY(source), HEK_LEN(source), + HEK_HASH(source), HEK_FLAGS(source)); + ptr_table_store(PL_shared_hek_table, source, shared); + } + HeKEY_hek(ret) = HeKEY_hek(shared); + } else HeKEY_hek(ret) = save_hek_flags(HeKEY(e), HeKLEN(e), HeHASH(e), HeKFLAGS(e)); @@ -542,7 +573,7 @@ S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, } TAINT_IF(save_taint); - if (!xhv->xhv_array /* !HvARRAY(hv) */ && !needs_store) { + if (!HvARRAY(hv) && !needs_store) { if (flags & HVhek_FREEKEY) Safefree(key); return Nullhe; @@ -568,15 +599,15 @@ S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, } /* ISSTORE */ } /* SvMAGICAL */ - if (!xhv->xhv_array /* !HvARRAY(hv) */) { + if (!HvARRAY(hv)) { if ((action & (HV_FETCH_LVALUE | HV_FETCH_ISSTORE)) #ifdef DYNAMIC_ENV_FETCH /* if it's an %ENV lookup, we may get it on the fly */ || (SvRMAGICAL((SV*)hv) && mg_find((SV*)hv, PERL_MAGIC_env)) #endif ) - Newz(503, xhv->xhv_array /* HvARRAY(hv) */, + Newz(503, HvARRAY(hv), PERL_HV_ARRAY_ALLOC_BYTES(xhv->xhv_max+1 /* HvMAX(hv)+1 */), - char); + HE*); #ifdef DYNAMIC_ENV_FETCH else if (action & HV_FETCH_ISEXISTS) { /* for an %ENV exists, if we do an insert it's by a recursive @@ -626,12 +657,11 @@ S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, n_links = 0; #ifdef DYNAMIC_ENV_FETCH - if (!xhv->xhv_array /* !HvARRAY(hv) */) entry = Null(HE*); + if (!HvARRAY(hv)) entry = Null(HE*); else #endif { - /* entry = (HvARRAY(hv))[hash & (I32) HvMAX(hv)]; */ - entry = ((HE**)xhv->xhv_array)[hash & (I32) xhv->xhv_max]; + entry = (HvARRAY(hv))[hash & (I32) HvMAX(hv)]; } for (; entry; ++n_links, entry = HeNEXT(entry)) { if (HeHASH(entry) != hash) /* strings can't be equal */ @@ -653,8 +683,8 @@ S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, /* Need to swap the key we have for a key with the flags we need. As keys are shared we can't just write to the flag, so we share the new one, unshare the old one. */ - HEK *new_hek = share_hek_flags(key, klen, hash, - masked_flags); + HEK *new_hek = HeKEY_hek(share_hek_flags(key, klen, hash, + masked_flags)); unshare_hek (HeKEY_hek(entry)); HeKEY_hek(entry) = new_hek; } @@ -680,11 +710,11 @@ S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, } /* LVAL fetch which actaully needs a store. */ val = NEWSV(61,0); - xhv->xhv_placeholders--; + HvPLACEHOLDERS(hv)--; } else { /* store */ if (val != &PL_sv_placeholder) - xhv->xhv_placeholders--; + HvPLACEHOLDERS(hv)--; } HeVAL(entry) = val; } else if (action & HV_FETCH_ISSTORE) { @@ -741,22 +771,22 @@ S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, /* Welcome to hv_store... */ - if (!xhv->xhv_array) { + if (!HvARRAY(hv)) { /* Not sure if we can get here. I think the only case of oentry being NULL is for %ENV with dynamic env fetch. But that should disappear with magic in the previous code. */ - Newz(503, xhv->xhv_array /* HvARRAY(hv) */, + Newz(503, HvARRAY(hv), PERL_HV_ARRAY_ALLOC_BYTES(xhv->xhv_max+1 /* HvMAX(hv)+1 */), - char); + HE*); } - oentry = &((HE**)xhv->xhv_array)[hash & (I32) xhv->xhv_max]; + oentry = &(HvARRAY(hv))[hash & (I32) xhv->xhv_max]; entry = new_HE(); /* share_hek_flags will do the free for us. This might be considered bad API design. */ if (HvSHAREKEYS(hv)) - HeKEY_hek(entry) = share_hek_flags(key, klen, hash, flags); + HeKEY_hek(entry) = HeKEY_hek(share_hek_flags(key, klen, hash, flags)); else /* gotta do the real thing */ HeKEY_hek(entry) = save_hek_flags(key, klen, hash, flags); HeVAL(entry) = val; @@ -764,7 +794,7 @@ S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, *oentry = entry; if (val == &PL_sv_placeholder) - xhv->xhv_placeholders++; + HvPLACEHOLDERS(hv)++; if (masked_flags & HVhek_ENABLEHVKFLAGS) HvHASKFLAGS_on(hv); @@ -941,7 +971,7 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, } } xhv = (XPVHV*)SvANY(hv); - if (!xhv->xhv_array /* !HvARRAY(hv) */) + if (!HvARRAY(hv)) return Nullsv; if (is_utf8) { @@ -975,8 +1005,7 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, masked_flags = (k_flags & HVhek_MASK); - /* oentry = &(HvARRAY(hv))[hash & (I32) HvMAX(hv)]; */ - oentry = &((HE**)xhv->xhv_array)[hash & (I32) xhv->xhv_max]; + oentry = &(HvARRAY(hv))[hash & (I32) HvMAX(hv)]; entry = *oentry; i = 1; for (; entry; i=0, oentry = &HeNEXT(entry), entry = *oentry) { @@ -1022,12 +1051,13 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, HeVAL(entry) = &PL_sv_placeholder; /* We'll be saving this slot, so the number of allocated keys * doesn't go down, but the number placeholders goes up */ - xhv->xhv_placeholders++; /* HvPLACEHOLDERS(hv)++ */ + HvPLACEHOLDERS(hv)++; } else { *oentry = HeNEXT(entry); if (i && !*oentry) xhv->xhv_fill--; /* HvFILL(hv)-- */ - if (entry == xhv->xhv_eiter /* HvEITER(hv) */) + if (xhv->xhv_aux && entry + == ((struct xpvhv_aux *)xhv->xhv_aux)->xhv_eiter /* HvEITER(hv) */) HvLAZYDEL_on(hv); else hv_free_ent(hv, entry); @@ -1055,7 +1085,7 @@ S_hsplit(pTHX_ HV *hv) const I32 oldsize = (I32) xhv->xhv_max+1; /* HvMAX(hv)+1 (sick) */ register I32 newsize = oldsize * 2; register I32 i; - register char *a = xhv->xhv_array; /* HvARRAY(hv) */ + char *a = (char*) HvARRAY(hv); register HE **aep; register HE **oentry; int longest_chain = 0; @@ -1085,19 +1115,19 @@ S_hsplit(pTHX_ HV *hv) PL_nomemok = FALSE; return; } - Copy(xhv->xhv_array /* HvARRAY(hv) */, a, oldsize * sizeof(HE*), char); + Copy(HvARRAY(hv), a, oldsize * sizeof(HE*), char); if (oldsize >= 64) { - offer_nice_chunk(xhv->xhv_array /* HvARRAY(hv) */, + offer_nice_chunk(HvARRAY(hv), PERL_HV_ARRAY_ALLOC_BYTES(oldsize)); } else - Safefree(xhv->xhv_array /* HvARRAY(hv) */); + Safefree(HvARRAY(hv)); #endif PL_nomemok = FALSE; Zero(&a[oldsize * sizeof(HE*)], (newsize-oldsize) * sizeof(HE*), char); /* zero 2nd half*/ xhv->xhv_max = --newsize; /* HvMAX(hv) = --newsize */ - xhv->xhv_array = a; /* HvARRAY(hv) = a */ + HvARRAY(hv) = (HE**) a; aep = (HE**)a; for (i=0; ixhv_array; + aep = HvARRAY(hv); for (i=0; ixhv_array); - xhv->xhv_array = a; /* HvARRAY(hv) = a */ + Safefree (HvARRAY(hv)); + HvARRAY(hv) = (HE **)a; } void @@ -1226,7 +1256,7 @@ Perl_hv_ksplit(pTHX_ HV *hv, IV newmax) if (newsize < newmax) return; /* overflow detection */ - a = xhv->xhv_array; /* HvARRAY(hv) */ + a = (char *) HvARRAY(hv); if (a) { PL_nomemok = TRUE; #if defined(STRANGE_MALLOC) || defined(MYMALLOC) @@ -1241,13 +1271,13 @@ Perl_hv_ksplit(pTHX_ HV *hv, IV newmax) PL_nomemok = FALSE; return; } - Copy(xhv->xhv_array /* HvARRAY(hv) */, a, oldsize * sizeof(HE*), char); + Copy(HvARRAY(hv), a, oldsize * sizeof(HE*), char); if (oldsize >= 64) { - offer_nice_chunk(xhv->xhv_array /* HvARRAY(hv) */, + offer_nice_chunk(HvARRAY(hv), PERL_HV_ARRAY_ALLOC_BYTES(oldsize)); } else - Safefree(xhv->xhv_array /* HvARRAY(hv) */); + Safefree(HvARRAY(hv)); #endif PL_nomemok = FALSE; Zero(&a[oldsize * sizeof(HE*)], (newsize-oldsize) * sizeof(HE*), char); /* zero 2nd half*/ @@ -1256,7 +1286,7 @@ Perl_hv_ksplit(pTHX_ HV *hv, IV newmax) Newz(0, a, PERL_HV_ARRAY_ALLOC_BYTES(newsize), char); } xhv->xhv_max = --newsize; /* HvMAX(hv) = --newsize */ - xhv->xhv_array = a; /* HvARRAY(hv) = a */ + HvARRAY(hv) = (HE **) a; if (!xhv->xhv_fill /* !HvFILL(hv) */) /* skip rest if no entries */ return; @@ -1307,8 +1337,7 @@ Perl_newHV(pTHX) xhv->xhv_max = 7; /* HvMAX(hv) = 7 (start with 8 buckets) */ xhv->xhv_fill = 0; /* HvFILL(hv) = 0 */ - xhv->xhv_pmroot = 0; /* HvPMROOT(hv) = 0 */ - (void)hv_iterinit(hv); /* so each() will start off right */ + xhv->xhv_aux = 0; return hv; } @@ -1350,7 +1379,7 @@ Perl_newHVhv(pTHX_ HV *ohv) ent = new_HE(); HeVAL(ent) = newSVsv(HeVAL(oent)); HeKEY_hek(ent) - = shared ? share_hek_flags(key, len, hash, flags) + = shared ? HeKEY_hek(share_hek_flags(key, len, hash, flags)) : save_hek_flags(key, len, hash, flags); if (prev) HeNEXT(prev) = ent; @@ -1369,8 +1398,8 @@ Perl_newHVhv(pTHX_ HV *ohv) else { /* Iterate over ohv, copying keys and values one at a time. */ HE *entry; - const I32 riter = HvRITER(ohv); - HE * const eiter = HvEITER(ohv); + const I32 riter = HvRITER_get(ohv); + HE * const eiter = HvEITER_get(ohv); /* Can we use fewer buckets? (hv_max is always 2^n-1) */ while (hv_max && hv_max + 1 >= hv_fill * 2) @@ -1383,8 +1412,8 @@ Perl_newHVhv(pTHX_ HV *ohv) newSVsv(HeVAL(entry)), HeHASH(entry), HeKFLAGS(entry)); } - HvRITER(ohv) = riter; - HvEITER(ohv) = eiter; + HvRITER_set(ohv, riter); + HvEITER_set(ohv, eiter); } return hv; @@ -1398,7 +1427,7 @@ Perl_hv_free_ent(pTHX_ HV *hv, register HE *entry) if (!entry) return; val = HeVAL(entry); - if (val && isGV(val) && GvCVu(val) && HvNAME(hv)) + if (val && isGV(val) && GvCVu(val) && HvNAME_get(hv)) PL_sub_generation++; /* may be deletion of method from stash */ SvREFCNT_dec(val); if (HeKLEN(entry) == HEf_SVKEY) { @@ -1417,7 +1446,7 @@ Perl_hv_delayfree_ent(pTHX_ HV *hv, register HE *entry) { if (!entry) return; - if (isGV(HeVAL(entry)) && GvCVu(HeVAL(entry)) && HvNAME(hv)) + if (isGV(HeVAL(entry)) && GvCVu(HeVAL(entry)) && HvNAME_get(hv)) PL_sub_generation++; /* may be deletion of method from stash */ sv_2mortal(HeVAL(entry)); /* free between statements */ if (HeKLEN(entry) == HEf_SVKEY) { @@ -1451,11 +1480,11 @@ Perl_hv_clear(pTHX_ HV *hv) xhv = (XPVHV*)SvANY(hv); - if (SvREADONLY(hv) && xhv->xhv_array != NULL) { + if (SvREADONLY(hv) && HvARRAY(hv) != NULL) { /* restricted hash: convert all keys to placeholders */ I32 i; for (i = 0; i <= (I32) xhv->xhv_max; i++) { - HE *entry = ((HE**)xhv->xhv_array)[i]; + HE *entry = (HvARRAY(hv))[i]; for (; entry; entry = HeNEXT(entry)) { /* not already placeholder */ if (HeVAL(entry) != &PL_sv_placeholder) { @@ -1467,7 +1496,7 @@ Perl_hv_clear(pTHX_ HV *hv) } SvREFCNT_dec(HeVAL(entry)); HeVAL(entry) = &PL_sv_placeholder; - xhv->xhv_placeholders++; /* HvPLACEHOLDERS(hv)++ */ + HvPLACEHOLDERS(hv)++; } } } @@ -1475,9 +1504,9 @@ Perl_hv_clear(pTHX_ HV *hv) } hfreeentries(hv); - xhv->xhv_placeholders = 0; /* HvPLACEHOLDERS(hv) = 0 */ - if (xhv->xhv_array /* HvARRAY(hv) */) - (void)memzero(xhv->xhv_array /* HvARRAY(hv) */, + HvPLACEHOLDERS_set(hv, 0); + if (HvARRAY(hv)) + (void)memzero(HvARRAY(hv), (xhv->xhv_max+1 /* HvMAX(hv)+1 */) * sizeof(HE*)); if (SvRMAGICAL(hv)) @@ -1486,7 +1515,9 @@ Perl_hv_clear(pTHX_ HV *hv) HvHASKFLAGS_off(hv); HvREHASH_off(hv); reset: - HvEITER(hv) = NULL; + if (xhv->xhv_aux) { + HvEITER_set(hv, NULL); + } } /* @@ -1527,7 +1558,7 @@ Perl_hv_clear_placeholders(pTHX_ HV *hv) *oentry = HeNEXT(entry); if (first && !*oentry) HvFILL(hv)--; /* This linked list is now empty. */ - if (HvEITER(hv)) + if (HvEITER_get(hv)) HvLAZYDEL_on(hv); else hv_free_ent(hv, entry); @@ -1558,6 +1589,7 @@ S_hfreeentries(pTHX_ HV *hv) register HE *entry; I32 riter; I32 max; + struct xpvhv_aux *iter; if (!hv) return; @@ -1587,7 +1619,18 @@ S_hfreeentries(pTHX_ HV *hv) } } HvARRAY(hv) = array; - (void)hv_iterinit(hv); + + iter = ((XPVHV*) SvANY(hv))->xhv_aux; + if (iter) { + entry = iter->xhv_eiter; /* HvEITER(hv) */ + if (entry && HvLAZYDEL(hv)) { /* was deleted earlier? */ + HvLAZYDEL_off(hv); + hv_free_ent(hv, entry); + } + Safefree(iter->xhv_name); + Safefree(iter); + ((XPVHV*) SvANY(hv))->xhv_aux = 0; + } } /* @@ -1602,26 +1645,40 @@ void Perl_hv_undef(pTHX_ HV *hv) { register XPVHV* xhv; + const char *name; if (!hv) return; DEBUG_A(Perl_hv_assert(aTHX_ hv)); xhv = (XPVHV*)SvANY(hv); hfreeentries(hv); - Safefree(xhv->xhv_array /* HvARRAY(hv) */); - if (HvNAME(hv)) { + Safefree(HvARRAY(hv)); + if ((name = HvNAME_get(hv))) { + /* FIXME - strlen HvNAME */ if(PL_stashcache) - hv_delete(PL_stashcache, HvNAME(hv), strlen(HvNAME(hv)), G_DISCARD); - Safefree(HvNAME(hv)); - HvNAME(hv) = 0; + hv_delete(PL_stashcache, name, strlen(name), G_DISCARD); + Perl_hv_name_set(aTHX_ hv, 0, 0, 0); } xhv->xhv_max = 7; /* HvMAX(hv) = 7 (it's a normal hash) */ - xhv->xhv_array = 0; /* HvARRAY(hv) = 0 */ - xhv->xhv_placeholders = 0; /* HvPLACEHOLDERS(hv) = 0 */ + HvARRAY(hv) = 0; + HvPLACEHOLDERS_set(hv, 0); if (SvRMAGICAL(hv)) mg_clear((SV*)hv); } +struct xpvhv_aux* +S_hv_auxinit(pTHX) { + struct xpvhv_aux *iter; + + New(0, iter, 1, struct xpvhv_aux); + + iter->xhv_riter = -1; /* HvRITER(hv) = -1 */ + iter->xhv_eiter = Null(HE*); /* HvEITER(hv) = Null(HE*) */ + iter->xhv_name = 0; + + return iter; +} + /* =for apidoc hv_iterinit @@ -1642,20 +1699,122 @@ Perl_hv_iterinit(pTHX_ HV *hv) { register XPVHV* xhv; HE *entry; + struct xpvhv_aux *iter; if (!hv) Perl_croak(aTHX_ "Bad hash"); xhv = (XPVHV*)SvANY(hv); - entry = xhv->xhv_eiter; /* HvEITER(hv) */ - if (entry && HvLAZYDEL(hv)) { /* was deleted earlier? */ - HvLAZYDEL_off(hv); - hv_free_ent(hv, entry); + + iter = xhv->xhv_aux; + if (iter) { + entry = iter->xhv_eiter; /* HvEITER(hv) */ + if (entry && HvLAZYDEL(hv)) { /* was deleted earlier? */ + HvLAZYDEL_off(hv); + hv_free_ent(hv, entry); + } + iter->xhv_riter = -1; /* HvRITER(hv) = -1 */ + iter->xhv_eiter = Null(HE*); /* HvEITER(hv) = Null(HE*) */ + } else { + xhv->xhv_aux = S_hv_auxinit(aTHX); } - xhv->xhv_riter = -1; /* HvRITER(hv) = -1 */ - xhv->xhv_eiter = Null(HE*); /* HvEITER(hv) = Null(HE*) */ + /* used to be xhv->xhv_fill before 5.004_65 */ return XHvTOTALKEYS(xhv); } + +I32 * +Perl_hv_riter_p(pTHX_ HV *hv) { + struct xpvhv_aux *iter; + + if (!hv) + Perl_croak(aTHX_ "Bad hash"); + + iter = ((XPVHV *)SvANY(hv))->xhv_aux; + if (!iter) { + ((XPVHV *)SvANY(hv))->xhv_aux = iter = S_hv_auxinit(aTHX); + } + return &(iter->xhv_riter); +} + +HE ** +Perl_hv_eiter_p(pTHX_ HV *hv) { + struct xpvhv_aux *iter; + + if (!hv) + Perl_croak(aTHX_ "Bad hash"); + + iter = ((XPVHV *)SvANY(hv))->xhv_aux; + if (!iter) { + ((XPVHV *)SvANY(hv))->xhv_aux = iter = S_hv_auxinit(aTHX); + } + return &(iter->xhv_eiter); +} + +void +Perl_hv_riter_set(pTHX_ HV *hv, I32 riter) { + struct xpvhv_aux *iter; + + if (!hv) + Perl_croak(aTHX_ "Bad hash"); + + + iter = ((XPVHV *)SvANY(hv))->xhv_aux; + if (!iter) { + if (riter == -1) + return; + + ((XPVHV *)SvANY(hv))->xhv_aux = iter = S_hv_auxinit(aTHX); + } + iter->xhv_riter = riter; +} + +void +Perl_hv_eiter_set(pTHX_ HV *hv, HE *eiter) { + struct xpvhv_aux *iter; + + if (!hv) + Perl_croak(aTHX_ "Bad hash"); + + iter = ((XPVHV *)SvANY(hv))->xhv_aux; + if (!iter) { + /* 0 is the default so don't go malloc()ing a new structure just to + hold 0. */ + if (!eiter) + return; + + ((XPVHV *)SvANY(hv))->xhv_aux = iter = S_hv_auxinit(aTHX); + } + iter->xhv_eiter = eiter; +} + + +char ** +Perl_hv_name_p(pTHX_ HV *hv) +{ + struct xpvhv_aux *iter = ((XPVHV *)SvANY(hv))->xhv_aux; + + if (!iter) { + ((XPVHV *)SvANY(hv))->xhv_aux = iter = S_hv_auxinit(aTHX); + } + return &(iter->xhv_name); +} + +void +Perl_hv_name_set(pTHX_ HV *hv, const char *name, STRLEN len, int flags) +{ + struct xpvhv_aux *iter = ((XPVHV *)SvANY(hv))->xhv_aux; + + if (iter) { + Safefree(iter->xhv_name); + } else { + if (name == 0) + return; + + ((XPVHV *)SvANY(hv))->xhv_aux = iter = S_hv_auxinit(aTHX); + } + iter->xhv_name = savepvn(name, len); +} + /* =for apidoc hv_iternext @@ -1701,11 +1860,22 @@ Perl_hv_iternext_flags(pTHX_ HV *hv, I32 flags) register HE *entry; HE *oldentry; MAGIC* mg; + struct xpvhv_aux *iter; if (!hv) Perl_croak(aTHX_ "Bad hash"); xhv = (XPVHV*)SvANY(hv); - oldentry = entry = xhv->xhv_eiter; /* HvEITER(hv) */ + iter = xhv->xhv_aux; + + if (!iter) { + /* Too many things (well, pp_each at least) merrily assume that you can + call iv_iternext without calling hv_iterinit, so we'll have to deal + with it. */ + hv_iterinit(hv); + iter = ((XPVHV *)SvANY(hv))->xhv_aux; + } + + oldentry = entry = iter->xhv_eiter; /* HvEITER(hv) */ if ((mg = SvTIED_mg((SV*)hv, PERL_MAGIC_tied))) { SV *key = sv_newmortal(); @@ -1718,7 +1888,7 @@ Perl_hv_iternext_flags(pTHX_ HV *hv, I32 flags) HEK *hek; /* one HE per MAGICAL hash */ - xhv->xhv_eiter = entry = new_HE(); /* HvEITER(hv) = new_HE() */ + iter->xhv_eiter = entry = new_HE(); /* HvEITER(hv) = new_HE() */ Zero(entry, 1, HE); Newz(54, k, HEK_BASESIZE + sizeof(SV*), char); hek = (HEK*)k; @@ -1735,7 +1905,7 @@ Perl_hv_iternext_flags(pTHX_ HV *hv, I32 flags) SvREFCNT_dec(HeVAL(entry)); Safefree(HeKEY_hek(entry)); del_HE(entry); - xhv->xhv_eiter = Null(HE*); /* HvEITER(hv) = Null(HE*) */ + iter->xhv_eiter = Null(HE*); /* HvEITER(hv) = Null(HE*) */ return Null(HE*); } #ifdef DYNAMIC_ENV_FETCH /* set up %ENV for iteration */ @@ -1743,10 +1913,13 @@ Perl_hv_iternext_flags(pTHX_ HV *hv, I32 flags) prime_env_iter(); #endif - if (!xhv->xhv_array /* !HvARRAY(hv) */) - Newz(506, xhv->xhv_array /* HvARRAY(hv) */, + if (!HvARRAY(hv)) { + char *darray; + Newz(506, darray, PERL_HV_ARRAY_ALLOC_BYTES(xhv->xhv_max+1 /* HvMAX(hv)+1 */), char); + HvARRAY(hv) = (HE**) darray; + } /* At start of hash, entry is NULL. */ if (entry) { @@ -1764,14 +1937,13 @@ Perl_hv_iternext_flags(pTHX_ HV *hv, I32 flags) while (!entry) { /* OK. Come to the end of the current list. Grab the next one. */ - xhv->xhv_riter++; /* HvRITER(hv)++ */ - if (xhv->xhv_riter > (I32)xhv->xhv_max /* HvRITER(hv) > HvMAX(hv) */) { + iter->xhv_riter++; /* HvRITER(hv)++ */ + if (iter->xhv_riter > (I32)xhv->xhv_max /* HvRITER(hv) > HvMAX(hv) */) { /* There is no next one. End of the hash. */ - xhv->xhv_riter = -1; /* HvRITER(hv) = -1 */ + iter->xhv_riter = -1; /* HvRITER(hv) = -1 */ break; } - /* entry = (HvARRAY(hv))[HvRITER(hv)]; */ - entry = ((HE**)xhv->xhv_array)[xhv->xhv_riter]; + entry = (HvARRAY(hv))[iter->xhv_riter]; if (!(flags & HV_ITERNEXT_WANTPLACEHOLDERS)) { /* If we have an entry, but it's a placeholder, don't count it. @@ -1792,7 +1964,7 @@ Perl_hv_iternext_flags(pTHX_ HV *hv, I32 flags) /*if (HvREHASH(hv) && entry && !HeKREHASH(entry)) PerlIO_printf(PerlIO_stderr(), "Awooga %p %p\n", hv, entry);*/ - xhv->xhv_eiter = entry; /* HvEITER(hv) = entry */ + iter->xhv_eiter = entry; /* HvEITER(hv) = entry */ return entry; } @@ -1991,8 +2163,7 @@ S_unshare_hek_or_pvn(pTHX_ HEK *hek, const char *str, I32 len, U32 hash) xhv = (XPVHV*)SvANY(PL_strtab); /* assert(xhv_array != 0) */ LOCK_STRTAB_MUTEX; - /* oentry = &(HvARRAY(hv))[hash & (I32) HvMAX(hv)]; */ - oentry = &((HE**)xhv->xhv_array)[hash & (I32) xhv->xhv_max]; + oentry = &(HvARRAY(PL_strtab))[hash & (I32) HvMAX(PL_strtab)]; if (hek) { for (entry = *oentry; entry; i=0, oentry = &HeNEXT(entry), entry = *oentry) { if (HeKEY_hek(entry) != hek) @@ -2066,10 +2237,10 @@ Perl_share_hek(pTHX_ const char *str, I32 len, register U32 hash) flags |= HVhek_WASUTF8 | HVhek_FREEKEY; } - return share_hek_flags (str, len, hash, flags); + return HeKEY_hek(share_hek_flags (str, len, hash, flags)); } -STATIC HEK * +STATIC HE * S_share_hek_flags(pTHX_ const char *str, I32 len, register U32 hash, int flags) { register XPVHV* xhv; @@ -2090,8 +2261,7 @@ S_share_hek_flags(pTHX_ const char *str, I32 len, register U32 hash, int flags) xhv = (XPVHV*)SvANY(PL_strtab); /* assert(xhv_array != 0) */ LOCK_STRTAB_MUTEX; - /* oentry = &(HvARRAY(hv))[hash & (I32) HvMAX(hv)]; */ - oentry = &((HE**)xhv->xhv_array)[hash & (I32) xhv->xhv_max]; + oentry = &(HvARRAY(PL_strtab))[hash & (I32) HvMAX(PL_strtab)]; for (entry = *oentry; entry; i=0, entry = HeNEXT(entry)) { if (HeHASH(entry) != hash) /* strings can't be equal */ continue; @@ -2124,9 +2294,49 @@ S_share_hek_flags(pTHX_ const char *str, I32 len, register U32 hash, int flags) if (flags & HVhek_FREEKEY) Safefree(str); - return HeKEY_hek(entry); + return entry; +} + +I32 * +Perl_hv_placeholders_p(pTHX_ HV *hv) +{ + dVAR; + MAGIC *mg = mg_find((SV*)hv, PERL_MAGIC_rhash); + + if (!mg) { + mg = sv_magicext((SV*)hv, 0, PERL_MAGIC_rhash, 0, 0, 0); + + if (!mg) { + Perl_die(aTHX_ "panic: hv_placeholders_p"); + } + } + return &(mg->mg_len); +} + + +I32 +Perl_hv_placeholders_get(pTHX_ HV *hv) +{ + dVAR; + MAGIC *mg = mg_find((SV*)hv, PERL_MAGIC_rhash); + + return mg ? mg->mg_len : 0; } +void +Perl_hv_placeholders_set(pTHX_ HV *hv, I32 ph) +{ + dVAR; + MAGIC *mg = mg_find((SV*)hv, PERL_MAGIC_rhash); + + if (mg) { + mg->mg_len = ph; + } else if (ph) { + if (!sv_magicext((SV*)hv, 0, PERL_MAGIC_rhash, 0, 0, ph)) + Perl_die(aTHX_ "panic: hv_placeholders_set"); + } + /* else we don't need to add magic to record 0 placeholders. */ +} /* =for apidoc hv_assert @@ -2145,8 +2355,8 @@ Perl_hv_assert(pTHX_ HV *hv) int placeholders = 0; int real = 0; int bad = 0; - const I32 riter = HvRITER(hv); - HE *eiter = HvEITER(hv); + const I32 riter = HvRITER_get(hv); + HE *eiter = HvEITER_get(hv); (void)hv_iterinit(hv); @@ -2194,8 +2404,8 @@ Perl_hv_assert(pTHX_ HV *hv) if (bad) { sv_dump((SV *)hv); } - HvRITER(hv) = riter; /* Restore hash iterator state */ - HvEITER(hv) = eiter; + HvRITER_set(hv, riter); /* Restore hash iterator state */ + HvEITER_set(hv, eiter); } /*