X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=hv.c;h=ebb10fbd345f1801694526bf7c1f9dc2b1f103b7;hb=458b44e7bc48569051e0eb9b5630ba87d7e5eed4;hp=adb5a4d777f32498b1365cf5e4dc3b7bcab65e06;hpb=4ac71550d23cca4632a2bcdfcb1d83a6bf705e45;p=p5sagit%2Fp5-mst-13.2.git diff --git a/hv.c b/hv.c index adb5a4d..ebb10fb 100644 --- a/hv.c +++ b/hv.c @@ -134,11 +134,15 @@ Perl_free_tied_hv_pool(pTHX) HEK * Perl_hek_dup(pTHX_ HEK *source, CLONE_PARAMS* param) { - HEK *shared = (HEK*)ptr_table_fetch(PL_ptr_table, source); + HEK *shared; PERL_ARGS_ASSERT_HEK_DUP; PERL_UNUSED_ARG(param); + if (!source) + return NULL; + + shared = (HEK*)ptr_table_fetch(PL_ptr_table, source); if (shared) { /* We already shared this hash key. */ (void)share_hek_hek(shared); @@ -388,8 +392,12 @@ Perl_hv_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, if (flags & HVhek_FREEKEY) Safefree(key); key = SvPV_const(keysv, klen); - flags = 0; is_utf8 = (SvUTF8(keysv) != 0); + if (SvIsCOW_shared_hash(keysv)) { + flags = HVhek_KEYCANONICAL | (is_utf8 ? HVhek_UTF8 : 0); + } else { + flags = 0; + } } else { is_utf8 = ((flags & HVhek_UTF8) ? TRUE : FALSE); } @@ -595,7 +603,7 @@ Perl_hv_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, } } - if (is_utf8) { + if (is_utf8 & !(flags & HVhek_KEYCANONICAL)) { char * const keysave = (char *)key; key = (char*)bytes_from_utf8((U8*)key, &klen, &is_utf8); if (is_utf8) @@ -606,6 +614,11 @@ Perl_hv_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, if (flags & HVhek_FREEKEY) Safefree(keysave); flags |= HVhek_WASUTF8 | HVhek_FREEKEY; + /* If the caller calculated a hash, it was on the sequence of + octets that are the UTF-8 form. We've now changed the sequence + of octets stored to that of the equivalent byte representation, + so the hash we need is different. */ + hash = 0; } } @@ -1430,8 +1443,10 @@ Perl_hv_copy_hints_hv(pTHX_ HV *const ohv) hv_iterinit(ohv); while ((entry = hv_iternext_flags(ohv, 0))) { SV *const sv = newSVsv(HeVAL(entry)); + SV *heksv = newSVhek(HeKEY_hek(entry)); sv_magic(sv, NULL, PERL_MAGIC_hintselem, - (char *)newSVhek (HeKEY_hek(entry)), HEf_SVKEY); + (char *)heksv, HEf_SVKEY); + SvREFCNT_dec(heksv); (void)hv_store_flags(hv, HeKEY(entry), HeKLEN(entry), sv, HeHASH(entry), HeKFLAGS(entry)); } @@ -1694,8 +1709,17 @@ S_hfreeentries(pTHX_ HV *hv) iter->xhv_eiter = NULL; /* HvEITER(hv) = NULL */ if((meta = iter->xhv_mro_meta)) { - if(meta->mro_linear_dfs) SvREFCNT_dec(meta->mro_linear_dfs); - if(meta->mro_linear_c3) SvREFCNT_dec(meta->mro_linear_c3); + if (meta->mro_linear_all) { + SvREFCNT_dec(MUTABLE_SV(meta->mro_linear_all)); + meta->mro_linear_all = NULL; + /* This is just acting as a shortcut pointer. */ + meta->mro_linear_current = NULL; + } else if (meta->mro_linear_current) { + /* Only the current MRO is stored, so this owns the data. + */ + SvREFCNT_dec(meta->mro_linear_current); + meta->mro_linear_current = NULL; + } if(meta->mro_nextmethod) SvREFCNT_dec(meta->mro_nextmethod); SvREFCNT_dec(meta->isa); Safefree(meta); @@ -2119,26 +2143,31 @@ Perl_hv_iternext_flags(pTHX_ HV *hv, I32 flags) } } } - while (!entry) { - /* OK. Come to the end of the current list. Grab the next one. */ - 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. */ - iter->xhv_riter = -1; /* HvRITER(hv) = -1 */ - break; - } - entry = (HvARRAY(hv))[iter->xhv_riter]; + /* Skip the entire loop if the hash is empty. */ + if ((flags & HV_ITERNEXT_WANTPLACEHOLDERS) + ? HvTOTALKEYS(hv) : HvUSEDKEYS(hv)) { + while (!entry) { + /* OK. Come to the end of the current list. Grab the next one. */ - if (!(flags & HV_ITERNEXT_WANTPLACEHOLDERS)) { - /* If we have an entry, but it's a placeholder, don't count it. - Try the next. */ - while (entry && HeVAL(entry) == &PL_sv_placeholder) - entry = HeNEXT(entry); + 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. */ + iter->xhv_riter = -1; /* HvRITER(hv) = -1 */ + break; + } + 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. + Try the next. */ + while (entry && HeVAL(entry) == &PL_sv_placeholder) + entry = HeNEXT(entry); + } + /* Will loop again if this linked list starts NULL + (for HV_ITERNEXT_WANTPLACEHOLDERS) + or if we run through it and find only placeholders. */ } - /* Will loop again if this linked list starts NULL - (for HV_ITERNEXT_WANTPLACEHOLDERS) - or if we run through it and find only placeholders. */ } if (oldentry && HvLAZYDEL(hv)) { /* was deleted earlier? */ @@ -2302,13 +2331,10 @@ S_unshare_hek_or_pvn(pTHX_ const HEK *hek, const char *str, I32 len, U32 hash) shared hek */ assert (he->shared_he_he.hent_hek == hek); - LOCK_STRTAB_MUTEX; if (he->shared_he_he.he_valu.hent_refcount - 1) { --he->shared_he_he.he_valu.hent_refcount; - UNLOCK_STRTAB_MUTEX; return; } - UNLOCK_STRTAB_MUTEX; hash = HEK_HASH(hek); } else if (len < 0) { @@ -2330,7 +2356,6 @@ S_unshare_hek_or_pvn(pTHX_ const HEK *hek, const char *str, I32 len, U32 hash) } */ xhv = (XPVHV*)SvANY(PL_strtab); /* assert(xhv_array != 0) */ - LOCK_STRTAB_MUTEX; first = oentry = &(HvARRAY(PL_strtab))[hash & (I32) HvMAX(PL_strtab)]; if (he) { const HE *const he_he = &(he->shared_he_he); @@ -2365,7 +2390,6 @@ S_unshare_hek_or_pvn(pTHX_ const HEK *hek, const char *str, I32 len, U32 hash) } } - UNLOCK_STRTAB_MUTEX; if (!entry && ckWARN_d(WARN_INTERNAL)) Perl_warner(aTHX_ packWARN(WARN_INTERNAL), "Attempt to free non-existent shared string '%s'%s" @@ -2430,7 +2454,6 @@ S_share_hek_flags(pTHX_ const char *str, I32 len, register U32 hash, int flags) */ /* assert(xhv_array != 0) */ - LOCK_STRTAB_MUTEX; entry = (HvARRAY(PL_strtab))[hindex]; for (;entry; entry = HeNEXT(entry)) { if (HeHASH(entry) != hash) /* strings can't be equal */ @@ -2488,7 +2511,6 @@ S_share_hek_flags(pTHX_ const char *str, I32 len, register U32 hash, int flags) } ++entry->he_valu.hent_refcount; - UNLOCK_STRTAB_MUTEX; if (flags & HVhek_FREEKEY) Safefree(str);