X-Git-Url: https://perl5.git.perl.org/perl5.git/blobdiff_plain/796b6530911f5ebd6a26275873610304e63d5d19..62b01c09f95477292e86289b27438aa97e5b8df0:/hv.c diff --git a/hv.c b/hv.c index c7e1eb1..85e42d1 100644 --- a/hv.c +++ b/hv.c @@ -390,7 +390,7 @@ Perl_hv_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, flags = is_utf8 ? HVhek_UTF8 : 0; } } else { - is_utf8 = ((flags & HVhek_UTF8) ? TRUE : FALSE); + is_utf8 = cBOOL(flags & HVhek_UTF8); } if (action & HV_DELETE) { @@ -766,7 +766,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, - "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))) { @@ -829,13 +829,6 @@ 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; - 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, @@ -937,8 +930,14 @@ S_hv_magic_check(HV *hv, bool *needs_copy, bool *needs_store) /* =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 */ @@ -957,7 +956,41 @@ Perl_hv_scalar(pTHX_ HV *hv) } sv = sv_newmortal(); - if (HvTOTALKEYS((const HV *)hv)) + sv_setuv(sv, HvUSEDKEYS(hv)); + + return sv; +} + +/* +=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); + } + + sv = sv_newmortal(); + if (HvUSEDKEYS((HV *)hv)) Perl_sv_setpvf(aTHX_ sv, "%ld/%ld", (long)HvFILL(hv), (long)HvMAX(hv) + 1); else @@ -996,7 +1029,7 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, 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 */ @@ -1135,7 +1168,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, - "Attempt to delete readonly key '%"SVf"' from" + "Attempt to delete readonly key '%" SVf "' from" " a restricted hash"); } if (k_flags & HVhek_FREEKEY) @@ -1166,8 +1199,73 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, sv_2mortal((SV *)gv) ); } - else if (klen == 3 && strnEQ(key, "ISA", 3)) + else if (klen == 3 && strEQs(key, "ISA") && GvAV(gv)) { + AV *isa = GvAV(gv); + MAGIC *mg = mg_find((SV*)isa, PERL_MAGIC_isa); + 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)); @@ -1191,12 +1289,6 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, 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 { @@ -1225,7 +1317,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, - "Attempt to delete disallowed key '%"SVf"' from" + "Attempt to delete disallowed key '%" SVf "' from" " a restricted hash"); } @@ -1288,10 +1380,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 - /* 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, @@ -1599,8 +1687,8 @@ Perl_hv_delayfree_ent(pTHX_ HV *hv, HE *entry) Frees the all the elements of a hash, leaving it empty. The XS equivalent of C<%hash = ()>. See also L. -If any destructors are triggered as a result, the hv itself may -be freed. +See L for a note about the hash possibly being invalid on +return. =cut */ @@ -1609,6 +1697,8 @@ void Perl_hv_clear(pTHX_ HV *hv) { dVAR; + SSize_t orig_ix; + XPVHV* xhv; if (!hv) return; @@ -1617,8 +1707,10 @@ Perl_hv_clear(pTHX_ HV *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; @@ -1631,7 +1723,7 @@ Perl_hv_clear(pTHX_ HV *hv) 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)); @@ -1656,7 +1748,12 @@ Perl_hv_clear(pTHX_ HV *hv) 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); } /* @@ -1787,12 +1884,6 @@ Perl_hfree_next_entry(pTHX_ HV *hv, STRLEN *indexp) 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) @@ -1834,10 +1925,8 @@ Undefines the hash. The XS equivalent of C. As well as freeing all the elements of the hash (like C), this 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. +See L for a note about the hash possibly being invalid on +return. =cut */ @@ -1847,10 +1936,11 @@ Perl_hv_undef_flags(pTHX_ HV *hv, U32 flags) { XPVHV* xhv; bool save; + SSize_t orig_ix; if (!hv) return; - save = !!SvREFCNT(hv); + save = cBOOL(SvREFCNT(hv)); DEBUG_A(Perl_hv_assert(aTHX_ hv)); xhv = (XPVHV*)SvANY(hv); @@ -1867,14 +1957,16 @@ Perl_hv_undef_flags(pTHX_ HV *hv, U32 flags) 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) { - 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); if (SvOOK(hv)) { @@ -1886,7 +1978,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 '%" - HEKf"'\n", HEKfARG(HvENAME_HEK(hv)))); + HEKf "'\n", HEKfARG(HvENAME_HEK(hv)))); (void)hv_deletehek(PL_stashcache, HvENAME_HEK(hv), G_DISCARD); } } @@ -1897,7 +1989,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 '%" - 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); @@ -1933,23 +2025,29 @@ Perl_hv_undef_flags(pTHX_ HV *hv, U32 flags) 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 -Returns the number of hash buckets that -happen to be in use. This function is -wrapped by the macro C. +Returns the number of hash buckets that happen to be in use. -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. +This function is wrapped by the macro C. + +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 */ @@ -1959,8 +2057,8 @@ Perl_hv_fill(pTHX_ HV *const 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. @@ -1968,12 +2066,12 @@ Perl_hv_fill(pTHX_ HV *const hv) if (HvTOTALKEYS(hv) < 2) return HvTOTALKEYS(hv); -#ifndef DEBUGGING - if (aux && aux->xhv_fill_lazy) - return aux->xhv_fill_lazy; -#endif - 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; @@ -1982,16 +2080,6 @@ Perl_hv_fill(pTHX_ HV *const hv) --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; } @@ -2036,7 +2124,6 @@ S_hv_auxinit_internal(struct xpvhv_aux *iter) { #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; @@ -2085,8 +2172,8 @@ S_hv_auxinit(pTHX_ HV *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). The return value is -currently only meaningful for hashes without tie magic. +keys in the hash, including placeholders (i.e. the same as C). +The return value is currently only meaningful for hashes without tie magic. NOTE: Before version 5.004_65, C used to return the number of hash buckets that happen to be in use. If you still need that esoteric @@ -2118,7 +2205,7 @@ Perl_hv_iterinit(pTHX_ HV *hv) hv_auxinit(hv); } - /* used to be xhv->xhv_fill before 5.004_65 */ + /* note this includes placeholders! */ return HvTOTALKEYS(hv); } @@ -2207,7 +2294,7 @@ 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_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); @@ -2314,7 +2401,7 @@ Perl_hv_ename_add(pTHX_ HV *hv, const char *name, U32 len, U32 flags) 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); @@ -2376,7 +2463,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_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; @@ -2413,9 +2500,10 @@ Perl_hv_ename_delete(pTHX_ HV *hv, const char *name, U32 len, U32 flags) 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)) + ) ) { aux->xhv_name_count = -count; } @@ -3055,7 +3143,7 @@ S_refcounted_he_value(pTHX_ const struct refcounted_he *he) 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; @@ -3078,7 +3166,7 @@ Perl_refcounted_he_chain_2hv(pTHX_ const struct refcounted_he *chain, U32 flags) 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, @@ -3192,7 +3280,7 @@ Perl_refcounted_he_fetch_pvn(pTHX_ const struct refcounted_he *chain, 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; @@ -3223,7 +3311,7 @@ Perl_refcounted_he_fetch_pvn(pTHX_ const struct refcounted_he *chain, } else { p++; - *q = (char) TWO_BYTE_UTF8_TO_NATIVE(c, *p); + *q = (char) EIGHT_BIT_UTF8_TO_NATIVE(c, *p); } } } @@ -3293,7 +3381,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) - 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)) @@ -3399,7 +3487,7 @@ Perl_refcounted_he_new_pvn(pTHX_ struct refcounted_he *parent, } else { p++; - *q = (char) TWO_BYTE_UTF8_TO_NATIVE(c, *p); + *q = (char) EIGHT_BIT_UTF8_TO_NATIVE(c, *p); } } } @@ -3481,7 +3569,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) - 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)) @@ -3607,7 +3695,7 @@ Perl_cop_fetch_label(pTHX_ COP *const cop, STRLEN *len, U32 *flags) { Save a label into a C. You need to set flags to C -for a utf-8 label. +for a UTF-8 label. =cut */