X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=hv.c;h=a37b26edb7fcd121f6dcbe205b55838f051bec5e;hb=b6bbf3fa3e9accb3710d8c05e0e3b107baaa1fee;hp=a2e9443fe7cdcc02784c198b80f612dba7415b7b;hpb=cbbf89328f29f925842d180c1410e324b297744d;p=p5sagit%2Fp5-mst-13.2.git diff --git a/hv.c b/hv.c index a2e9443..a37b26e 100644 --- a/hv.c +++ b/hv.c @@ -1,7 +1,7 @@ /* hv.c * * Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - * 2000, 2001, 2002, 2003, 2004, 2005, by Larry Wall and others + * 2000, 2001, 2002, 2003, 2004, 2005, 2006, by Larry Wall and others * * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the README file. @@ -39,14 +39,14 @@ static const char S_strtab_error[] STATIC void S_more_he(pTHX) { + dVAR; HE* he; HE* heend; - Newx(he, PERL_ARENA_SIZE/sizeof(HE), HE); - HeNEXT(he) = (HE*) PL_body_arenaroots[HE_SVSLOT]; - PL_body_arenaroots[HE_SVSLOT] = he; + + he = (HE*) Perl_get_arena(aTHX_ PERL_ARENA_SIZE); heend = &he[PERL_ARENA_SIZE / sizeof(HE) - 1]; - PL_body_roots[HE_SVSLOT] = ++he; + PL_body_roots[HE_SVSLOT] = he; while (he < heend) { HeNEXT(he) = (HE*)(he + 1); he++; @@ -64,6 +64,7 @@ S_more_he(pTHX) STATIC HE* S_new_he(pTHX) { + dVAR; HE* he; void ** const root = &PL_body_roots[HE_SVSLOT]; @@ -90,7 +91,7 @@ S_new_he(pTHX) #endif STATIC HEK * -S_save_hek_flags(pTHX_ const char *str, I32 len, U32 hash, int flags) +S_save_hek_flags(const char *str, I32 len, U32 hash, int flags) { const int flags_masked = flags & HVhek_MASK; char *k; @@ -115,6 +116,7 @@ S_save_hek_flags(pTHX_ const char *str, I32 len, U32 hash, int flags) void Perl_free_tied_hv_pool(pTHX) { + dVAR; HE *he = PL_hv_fetch_ent_mh; while (he) { HE * const ohe = he; @@ -122,7 +124,7 @@ Perl_free_tied_hv_pool(pTHX) he = HeNEXT(he); del_HE(ohe); } - PL_hv_fetch_ent_mh = Nullhe; + PL_hv_fetch_ent_mh = NULL; } #if defined(USE_ITHREADS) @@ -152,7 +154,7 @@ Perl_he_dup(pTHX_ const HE *e, bool shared, CLONE_PARAMS* param) HE *ret; if (!e) - return Nullhe; + return NULL; /* look for it in the table first */ ret = (HE*)ptr_table_fetch(PL_ptr_table, e); if (ret) @@ -369,7 +371,7 @@ Perl_hv_fetch(pTHX_ HV *hv, const char *key, I32 klen_i32, I32 lval) } hek = hv_fetch_common (hv, NULL, key, klen, flags, lval ? (HV_FETCH_JUST_SV | HV_FETCH_LVALUE) : HV_FETCH_JUST_SV, - Nullsv, 0); + NULL, 0); return hek ? &HeVAL(hek) : NULL; } @@ -414,7 +416,7 @@ HE * Perl_hv_fetch_ent(pTHX_ HV *hv, SV *keysv, I32 lval, register U32 hash) { return hv_fetch_common(hv, keysv, NULL, 0, 0, - (lval ? HV_FETCH_LVALUE : 0), Nullsv, hash); + (lval ? HV_FETCH_LVALUE : 0), NULL, hash); } STATIC HE * @@ -430,7 +432,7 @@ S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, int masked_flags; if (!hv) - return 0; + return NULL; if (keysv) { if (flags & HVhek_FREEKEY) @@ -444,8 +446,7 @@ S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, xhv = (XPVHV*)SvANY(hv); if (SvMAGICAL(hv)) { - if (SvRMAGICAL(hv) && !(action & (HV_FETCH_ISSTORE|HV_FETCH_ISEXISTS))) - { + if (SvRMAGICAL(hv) && !(action & (HV_FETCH_ISSTORE|HV_FETCH_ISEXISTS))) { if (mg_find((SV*)hv, PERL_MAGIC_tied) || SvGMAGICAL((SV*)hv)) { sv = sv_newmortal(); @@ -472,7 +473,7 @@ S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, Newx(k, HEK_BASESIZE + sizeof(SV*), char); HeKEY_hek(entry) = (HEK*)k; } - HeNEXT(entry) = Nullhe; + HeNEXT(entry) = NULL; HeSVKEY_set(entry, keysv); HeVAL(entry) = sv; sv_upgrade(sv, SVt_PVLV); @@ -496,10 +497,10 @@ S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, const char * const nkey = strupr(savepvn(key,klen)); /* Note that this fetch is for nkey (the uppercased key) whereas the store is for key (the original) */ - entry = hv_fetch_common(hv, Nullsv, nkey, klen, + entry = hv_fetch_common(hv, NULL, nkey, klen, HVhek_FREEKEY, /* free nkey */ 0 /* non-LVAL fetch */, - Nullsv /* no value */, + NULL /* no value */, 0 /* compute hash */); if (!entry && (action & HV_FETCH_LVALUE)) { /* This call will free key if necessary. @@ -507,7 +508,7 @@ S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, call optimise. */ entry = hv_fetch_common(hv, keysv, key, klen, flags, HV_FETCH_ISSTORE, - NEWSV(61,0), hash); + newSV(0), hash); } else { if (flags & HVhek_FREEKEY) Safefree(key); @@ -550,7 +551,7 @@ S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, /* Will need to free this, so set FREEKEY flag. */ key = savepvn(key,klen); key = (const char*)strupr((char*)key); - is_utf8 = 0; + is_utf8 = FALSE; hash = 0; keysv = 0; @@ -581,10 +582,10 @@ S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, } TAINT_IF(save_taint); - if (!HvARRAY(hv) && !needs_store) { + if (!needs_store) { if (flags & HVhek_FREEKEY) Safefree(key); - return Nullhe; + return NULL; } #ifdef ENV_IS_CASELESS else if (mg_find((SV*)hv, PERL_MAGIC_env)) { @@ -593,7 +594,7 @@ S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, /* Will need to free this, so set FREEKEY flag. */ key = savepvn(key,klen); key = (const char*)strupr((char*)key); - is_utf8 = 0; + is_utf8 = FALSE; hash = 0; keysv = 0; @@ -635,7 +636,7 @@ S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, } if (is_utf8) { - char * const keysave = (char * const)key; + char * const keysave = (char *)key; key = (char*)bytes_from_utf8((U8*)key, &klen, &is_utf8); if (is_utf8) flags |= HVhek_UTF8; @@ -667,7 +668,7 @@ S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, masked_flags = (flags & HVhek_MASK); #ifdef DYNAMIC_ENV_FETCH - if (!HvARRAY(hv)) entry = Null(HE*); + if (!HvARRAY(hv)) entry = NULL; else #endif { @@ -693,7 +694,7 @@ 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, + HEK * const new_hek = share_hek_flags(key, klen, hash, masked_flags); unshare_hek (HeKEY_hek(entry)); HeKEY_hek(entry) = new_hek; @@ -727,7 +728,7 @@ S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, break; } /* LVAL fetch which actaully needs a store. */ - val = NEWSV(61,0); + val = newSV(0); HvPLACEHOLDERS(hv)--; } else { /* store */ @@ -774,7 +775,7 @@ S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, return 0; } if (action & HV_FETCH_LVALUE) { - val = NEWSV(61,0); + val = newSV(0); if (SvMAGICAL(hv)) { /* At this point the old hv_fetch code would call to hv_store, which in turn might do some tied magic. So we need to make that @@ -829,7 +830,7 @@ S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, { const HE *counter = HeNEXT(entry); - xhv->xhv_keys++; /* HvKEYS(hv)++ */ + xhv->xhv_keys++; /* HvTOTALKEYS(hv)++ */ if (!counter) { /* initial entry? */ xhv->xhv_fill++; /* HvFILL(hv)++ */ } else if (xhv->xhv_keys > (IV)xhv->xhv_max) { @@ -856,7 +857,7 @@ S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, } STATIC void -S_hv_magic_check(pTHX_ HV *hv, bool *needs_copy, bool *needs_store) +S_hv_magic_check(HV *hv, bool *needs_copy, bool *needs_store) { const MAGIC *mg = SvMAGIC(hv); *needs_copy = FALSE; @@ -917,13 +918,14 @@ SV * Perl_hv_delete(pTHX_ HV *hv, const char *key, I32 klen_i32, I32 flags) { STRLEN klen; - int k_flags = 0; + int k_flags; if (klen_i32 < 0) { klen = -klen_i32; - k_flags |= HVhek_UTF8; + k_flags = HVhek_UTF8; } else { klen = klen_i32; + k_flags = 0; } return hv_delete_common(hv, NULL, key, klen, k_flags, flags, 0); } @@ -955,12 +957,11 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, register HE *entry; register HE **oentry; HE *const *first_entry; - SV *sv; bool is_utf8; int masked_flags; if (!hv) - return Nullsv; + return NULL; if (keysv) { if (k_flags & HVhek_FREEKEY) @@ -978,9 +979,10 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, hv_magic_check (hv, &needs_copy, &needs_store); if (needs_copy) { + SV *sv; entry = hv_fetch_common(hv, keysv, key, klen, k_flags & ~HVhek_FREEKEY, HV_FETCH_LVALUE, - Nullsv, hash); + NULL, hash); sv = entry ? HeVAL(entry) : NULL; if (sv) { if (SvMAGICAL(sv)) { @@ -992,7 +994,7 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, sv_unmagic(sv, PERL_MAGIC_tiedelem); return sv; } - return Nullsv; /* element cannot be deleted */ + return NULL; /* element cannot be deleted */ } #ifdef ENV_IS_CASELESS else if (mg_find((SV*)hv, PERL_MAGIC_env)) { @@ -1012,7 +1014,7 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, } xhv = (XPVHV*)SvANY(hv); if (!HvARRAY(hv)) - return Nullsv; + return NULL; if (is_utf8) { const char * const keysave = key; @@ -1048,6 +1050,7 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, first_entry = oentry = &(HvARRAY(hv))[hash & (I32) HvMAX(hv)]; entry = *oentry; for (; entry; oentry = &HeNEXT(entry), entry = *oentry) { + SV *sv; if (HeHASH(entry) != hash) /* strings can't be equal */ continue; if (HeKLEN(entry) != (I32)klen) @@ -1064,14 +1067,13 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, } /* if placeholder is here, it's already been deleted.... */ - if (HeVAL(entry) == &PL_sv_placeholder) - { - if (k_flags & HVhek_FREEKEY) - Safefree(key); - return Nullsv; + if (HeVAL(entry) == &PL_sv_placeholder) { + if (k_flags & HVhek_FREEKEY) + Safefree(key); + return NULL; } - else if (SvREADONLY(hv) && HeVAL(entry) && SvREADONLY(HeVAL(entry))) { - S_hv_notallowed(aTHX_ k_flags, key, klen, + if (SvREADONLY(hv) && HeVAL(entry) && SvREADONLY(HeVAL(entry))) { + hv_notallowed(k_flags, key, klen, "Attempt to delete readonly key '%"SVf"' from" " a restricted hash"); } @@ -1079,7 +1081,7 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, Safefree(key); if (d_flags & G_DISCARD) - sv = Nullsv; + sv = NULL; else { sv = sv_2mortal(HeVAL(entry)); HeVAL(entry) = &PL_sv_placeholder; @@ -1106,26 +1108,27 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen, HvLAZYDEL_on(hv); else hv_free_ent(hv, entry); - xhv->xhv_keys--; /* HvKEYS(hv)-- */ + xhv->xhv_keys--; /* HvTOTALKEYS(hv)-- */ if (xhv->xhv_keys == 0) HvHASKFLAGS_off(hv); } return sv; } if (SvREADONLY(hv)) { - S_hv_notallowed(aTHX_ k_flags, key, klen, + hv_notallowed(k_flags, key, klen, "Attempt to delete disallowed key '%"SVf"' from" " a restricted hash"); } if (k_flags & HVhek_FREEKEY) Safefree(key); - return Nullsv; + return NULL; } STATIC void S_hsplit(pTHX_ HV *hv) { + dVAR; register XPVHV* xhv = (XPVHV*)SvANY(hv); const I32 oldsize = (I32) xhv->xhv_max+1; /* HvMAX(hv)+1 (sick) */ register I32 newsize = oldsize * 2; @@ -1295,6 +1298,7 @@ S_hsplit(pTHX_ HV *hv) void Perl_hv_ksplit(pTHX_ HV *hv, IV newmax) { + dVAR; register XPVHV* xhv = (XPVHV*)SvANY(hv); const I32 oldsize = (I32) xhv->xhv_max+1; /* HvMAX(hv)+1 (sick) */ register I32 newsize; @@ -1363,8 +1367,9 @@ Perl_hv_ksplit(pTHX_ HV *hv, IV newmax) if (!*aep) /* non-existent */ continue; for (oentry = aep, entry = *aep; entry; entry = *oentry) { - register I32 j; - if ((j = (HeHASH(entry) & newsize)) != i) { + register I32 j = (HeHASH(entry) & newsize); + + if (j != i) { j -= i; *oentry = HeNEXT(entry); if (!(HeNEXT(entry) = aep[j])) @@ -1392,7 +1397,7 @@ HV * Perl_newHV(pTHX) { register XPVHV* xhv; - HV * const hv = (HV*)NEWSV(502,0); + HV * const hv = (HV*)newSV(0); sv_upgrade((SV *)hv, SVt_PVHV); xhv = (XPVHV*)SvANY(hv); @@ -1428,7 +1433,7 @@ Perl_newHVhv(pTHX_ HV *ohv) /* In each bucket... */ for (i = 0; i <= hv_max; i++) { - HE *prev = NULL, *ent = NULL; + HE *prev = NULL; HE *oent = oents[i]; if (!oent) { @@ -1442,8 +1447,8 @@ Perl_newHVhv(pTHX_ HV *ohv) const char * const key = HeKEY(oent); const STRLEN len = HeKLEN(oent); const int flags = HeKFLAGS(oent); + HE * const ent = new_HE(); - ent = new_HE(); HeVAL(ent) = newSVsv(HeVAL(oent)); HeKEY_hek(ent) = shared ? share_hek_flags(key, len, hash, flags) @@ -1486,9 +1491,43 @@ Perl_newHVhv(pTHX_ HV *ohv) return hv; } +/* A rather specialised version of newHVhv for copying %^H, ensuring all the + magic stays on it. */ +HV * +Perl_hv_copy_hints_hv(pTHX_ HV *const ohv) +{ + HV * const hv = newHV(); + STRLEN hv_fill; + + if (ohv && (hv_fill = HvFILL(ohv))) { + STRLEN hv_max = HvMAX(ohv); + HE *entry; + const I32 riter = HvRITER_get(ohv); + HE * const eiter = HvEITER_get(ohv); + + while (hv_max && hv_max + 1 >= hv_fill * 2) + hv_max = hv_max / 2; + HvMAX(hv) = hv_max; + + hv_iterinit(ohv); + while ((entry = hv_iternext_flags(ohv, 0))) { + SV *const sv = newSVsv(HeVAL(entry)); + sv_magic(sv, NULL, PERL_MAGIC_hintselem, + (char *)newSVhek (HeKEY_hek(entry)), HEf_SVKEY); + hv_store_flags(hv, HeKEY(entry), HeKLEN(entry), + sv, HeHASH(entry), HeKFLAGS(entry)); + } + HvRITER_set(ohv, riter); + HvEITER_set(ohv, eiter); + } + hv_magic(hv, NULL, PERL_MAGIC_hints); + return hv; +} + void Perl_hv_free_ent(pTHX_ HV *hv, register HE *entry) { + dVAR; SV *val; if (!entry) @@ -1511,6 +1550,7 @@ Perl_hv_free_ent(pTHX_ HV *hv, register HE *entry) void Perl_hv_delayfree_ent(pTHX_ HV *hv, register HE *entry) { + dVAR; if (!entry) return; /* SvREFCNT_inc to counter the SvREFCNT_dec in hv_free_ent */ @@ -1550,7 +1590,7 @@ Perl_hv_clear(pTHX_ HV *hv) /* not already placeholder */ if (HeVAL(entry) != &PL_sv_placeholder) { if (HeVAL(entry) && SvREADONLY(HeVAL(entry))) { - SV* keysv = hv_iterkeysv(entry); + SV* const keysv = hv_iterkeysv(entry); Perl_croak(aTHX_ "Attempt to delete readonly key '%"SVf"' from a restricted hash", keysv); @@ -1599,7 +1639,16 @@ void Perl_hv_clear_placeholders(pTHX_ HV *hv) { dVAR; - I32 items = (I32)HvPLACEHOLDERS_get(hv); + const U32 items = (U32)HvPLACEHOLDERS_get(hv); + + if (items) + clear_placeholders(hv, items); +} + +static void +S_clear_placeholders(pTHX_ HV *hv, U32 items) +{ + dVAR; I32 i; if (items == 0) @@ -1608,7 +1657,7 @@ Perl_hv_clear_placeholders(pTHX_ HV *hv) i = HvMAX(hv); do { /* Loop down the linked list heads */ - bool first = 1; + bool first = TRUE; HE **oentry = &(HvARRAY(hv))[i]; HE *entry; @@ -1632,7 +1681,7 @@ Perl_hv_clear_placeholders(pTHX_ HV *hv) } } else { oentry = &HeNEXT(entry); - first = 0; + first = FALSE; } } } while (--i >= 0); @@ -1673,7 +1722,7 @@ S_hfreeentries(pTHX_ HV *hv) /* This is the one we're going to try to empty. First time round it's the original array. (Hopefully there will only be 1 time round) */ - HE **array = HvARRAY(hv); + HE ** const array = HvARRAY(hv); I32 i = HvMAX(hv); /* Because we have taken xhv_name out, the only allocated pointer @@ -1711,7 +1760,7 @@ S_hfreeentries(pTHX_ HV *hv) hv_free_ent(hv, entry); } iter->xhv_riter = -1; /* HvRITER(hv) = -1 */ - iter->xhv_eiter = Null(HE*); /* HvEITER(hv) = Null(HE*) */ + iter->xhv_eiter = NULL; /* HvEITER(hv) = NULL */ /* There are now no allocated pointers in the aux structure. */ @@ -1763,7 +1812,7 @@ S_hfreeentries(pTHX_ HV *hv) if (--attempts == 0) { Perl_die(aTHX_ "panic: hfreeentries failed to free hash - something is repeatedly re-creating entries"); } - }; + } HvARRAY(hv) = orig_array; @@ -1788,6 +1837,7 @@ Undefines the hash. void Perl_hv_undef(pTHX_ HV *hv) { + dVAR; register XPVHV* xhv; const char *name; @@ -1799,7 +1849,7 @@ Perl_hv_undef(pTHX_ HV *hv) if ((name = HvNAME_get(hv))) { if(PL_stashcache) hv_delete(PL_stashcache, name, HvNAMELEN_get(hv), G_DISCARD); - hv_name_set(hv, Nullch, 0, 0); + hv_name_set(hv, NULL, 0, 0); } SvFLAGS(hv) &= ~SVf_OOK; Safefree(HvARRAY(hv)); @@ -1812,7 +1862,7 @@ Perl_hv_undef(pTHX_ HV *hv) } static struct xpvhv_aux* -S_hv_auxinit(pTHX_ HV *hv) { +S_hv_auxinit(HV *hv) { struct xpvhv_aux *iter; char *array; @@ -1830,7 +1880,7 @@ S_hv_auxinit(pTHX_ HV *hv) { iter = HvAUX(hv); iter->xhv_riter = -1; /* HvRITER(hv) = -1 */ - iter->xhv_eiter = Null(HE*); /* HvEITER(hv) = Null(HE*) */ + iter->xhv_eiter = NULL; /* HvEITER(hv) = NULL */ iter->xhv_name = 0; iter->xhv_backreferences = 0; return iter; @@ -1858,16 +1908,16 @@ Perl_hv_iterinit(pTHX_ HV *hv) Perl_croak(aTHX_ "Bad hash"); if (SvOOK(hv)) { - struct xpvhv_aux *iter = HvAUX(hv); + struct xpvhv_aux * const iter = HvAUX(hv); HE * const 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*) */ + iter->xhv_eiter = NULL; /* HvEITER(hv) = NULL */ } else { - S_hv_auxinit(aTHX_ hv); + hv_auxinit(hv); } /* used to be xhv->xhv_fill before 5.004_65 */ @@ -1881,7 +1931,7 @@ Perl_hv_riter_p(pTHX_ HV *hv) { if (!hv) Perl_croak(aTHX_ "Bad hash"); - iter = SvOOK(hv) ? HvAUX(hv) : S_hv_auxinit(aTHX_ hv); + iter = SvOOK(hv) ? HvAUX(hv) : hv_auxinit(hv); return &(iter->xhv_riter); } @@ -1892,7 +1942,7 @@ Perl_hv_eiter_p(pTHX_ HV *hv) { if (!hv) Perl_croak(aTHX_ "Bad hash"); - iter = SvOOK(hv) ? HvAUX(hv) : S_hv_auxinit(aTHX_ hv); + iter = SvOOK(hv) ? HvAUX(hv) : hv_auxinit(hv); return &(iter->xhv_eiter); } @@ -1909,7 +1959,7 @@ Perl_hv_riter_set(pTHX_ HV *hv, I32 riter) { if (riter == -1) return; - iter = S_hv_auxinit(aTHX_ hv); + iter = hv_auxinit(hv); } iter->xhv_riter = riter; } @@ -1929,19 +1979,23 @@ Perl_hv_eiter_set(pTHX_ HV *hv, HE *eiter) { if (!eiter) return; - iter = S_hv_auxinit(aTHX_ hv); + iter = hv_auxinit(hv); } iter->xhv_eiter = eiter; } void -Perl_hv_name_set(pTHX_ HV *hv, const char *name, I32 len, int flags) +Perl_hv_name_set(pTHX_ HV *hv, const char *name, U32 len, U32 flags) { + dVAR; struct xpvhv_aux *iter; U32 hash; PERL_UNUSED_ARG(flags); + if (len > I32_MAX) + Perl_croak(aTHX_ "panic: hv name too long (%"UVuf")", (UV) len); + if (SvOOK(hv)) { iter = HvAUX(hv); if (iter->xhv_name) { @@ -1951,7 +2005,7 @@ Perl_hv_name_set(pTHX_ HV *hv, const char *name, I32 len, int flags) if (name == 0) return; - iter = S_hv_auxinit(aTHX_ hv); + iter = hv_auxinit(hv); } PERL_HASH(hash, name, len); iter->xhv_name = name ? share_hek(name, len, hash) : 0; @@ -1959,9 +2013,8 @@ Perl_hv_name_set(pTHX_ HV *hv, const char *name, I32 len, int flags) AV ** Perl_hv_backreferences_p(pTHX_ HV *hv) { - struct xpvhv_aux *iter; - - iter = SvOOK(hv) ? HvAUX(hv) : S_hv_auxinit(aTHX_ hv); + struct xpvhv_aux * const iter = SvOOK(hv) ? HvAUX(hv) : hv_auxinit(hv); + PERL_UNUSED_CONTEXT; return &(iter->xhv_backreferences); } @@ -2054,15 +2107,15 @@ Perl_hv_iternext_flags(pTHX_ HV *hv, I32 flags) magic_nextpack((SV*) hv,mg,key); if (SvOK(key)) { /* force key to stay around until next time */ - HeSVKEY_set(entry, SvREFCNT_inc(key)); + HeSVKEY_set(entry, SvREFCNT_inc_simple_NN(key)); return entry; /* beware, hent_val is not set */ } if (HeVAL(entry)) SvREFCNT_dec(HeVAL(entry)); Safefree(HeKEY_hek(entry)); del_HE(entry); - iter->xhv_eiter = Null(HE*); /* HvEITER(hv) = Null(HE*) */ - return Null(HE*); + iter->xhv_eiter = NULL; /* HvEITER(hv) = NULL */ + return NULL; } #ifdef DYNAMIC_ENV_FETCH /* set up %ENV for iteration */ if (!entry && SvRMAGICAL((SV*)hv) && mg_find((SV*)hv, PERL_MAGIC_env)) { @@ -2249,11 +2302,11 @@ Perl_unshare_hek(pTHX_ HEK *hek) STATIC void S_unshare_hek_or_pvn(pTHX_ const HEK *hek, const char *str, I32 len, U32 hash) { + dVAR; register XPVHV* xhv; HE *entry; register HE **oentry; HE **first; - bool found = 0; bool is_utf8 = FALSE; int k_flags = 0; const char * const save = str; @@ -2270,8 +2323,8 @@ S_unshare_hek_or_pvn(pTHX_ const HEK *hek, const char *str, I32 len, U32 hash) assert (he->shared_he_he.hent_hek == hek); LOCK_STRTAB_MUTEX; - if (he->shared_he_he.hent_val - 1) { - --he->shared_he_he.hent_val; + if (he->shared_he_he.he_valu.hent_refcount - 1) { + --he->shared_he_he.he_valu.hent_refcount; UNLOCK_STRTAB_MUTEX; return; } @@ -2290,9 +2343,9 @@ S_unshare_hek_or_pvn(pTHX_ const HEK *hek, const char *str, I32 len, U32 hash) k_flags |= HVhek_WASUTF8 | HVhek_FREEKEY; } - /* what follows is the moral equivalent of: + /* what follows was the moral equivalent of: if ((Svp = hv_fetch(PL_strtab, tmpsv, FALSE, hash))) { - if (--*Svp == Nullsv) + if (--*Svp == NULL) hv_delete(PL_strtab, str, len, G_DISCARD, hash); } */ xhv = (XPVHV*)SvANY(PL_strtab); @@ -2302,10 +2355,8 @@ S_unshare_hek_or_pvn(pTHX_ const HEK *hek, const char *str, I32 len, U32 hash) if (he) { const HE *const he_he = &(he->shared_he_he); for (entry = *oentry; entry; oentry = &HeNEXT(entry), entry = *oentry) { - if (entry != he_he) - continue; - found = 1; - break; + if (entry == he_he) + break; } } else { const int flags_masked = k_flags & HVhek_MASK; @@ -2318,25 +2369,24 @@ S_unshare_hek_or_pvn(pTHX_ const HEK *hek, const char *str, I32 len, U32 hash) continue; if (HeKFLAGS(entry) != flags_masked) continue; - found = 1; break; } } - if (found) { - if (--HeVAL(entry) == Nullsv) { + if (entry) { + if (--entry->he_valu.hent_refcount == 0) { *oentry = HeNEXT(entry); if (!*first) { /* There are now no entries in our slot. */ xhv->xhv_fill--; /* HvFILL(hv)-- */ } Safefree(entry); - xhv->xhv_keys--; /* HvKEYS(hv)-- */ + xhv->xhv_keys--; /* HvTOTALKEYS(hv)-- */ } } UNLOCK_STRTAB_MUTEX; - if (!found && ckWARN_d(WARN_INTERNAL)) + if (!entry && ckWARN_d(WARN_INTERNAL)) Perl_warner(aTHX_ packWARN(WARN_INTERNAL), "Attempt to free non-existent shared string '%s'%s" pTHX__FORMAT, @@ -2380,6 +2430,7 @@ Perl_share_hek(pTHX_ const char *str, I32 len, register U32 hash) STATIC HEK * S_share_hek_flags(pTHX_ const char *str, I32 len, register U32 hash, int flags) { + dVAR; register HE *entry; const int flags_masked = flags & HVhek_MASK; const U32 hindex = hash & (I32) HvMAX(PL_strtab); @@ -2387,7 +2438,7 @@ S_share_hek_flags(pTHX_ const char *str, I32 len, register U32 hash, int flags) /* what follows is the moral equivalent of: if (!(Svp = hv_fetch(PL_strtab, str, len, FALSE))) - hv_store(PL_strtab, str, len, Nullsv, hash); + hv_store(PL_strtab, str, len, NULL, hash); Can't rehash the shared string table, so not sure if it's worth counting the number of entries in the linked list @@ -2439,11 +2490,11 @@ S_share_hek_flags(pTHX_ const char *str, I32 len, register U32 hash, int flags) /* Still "point" to the HEK, so that other code need not know what we're up to. */ HeKEY_hek(entry) = hek; - HeVAL(entry) = Nullsv; + entry->he_valu.hent_refcount = 0; HeNEXT(entry) = next; *head = entry; - xhv->xhv_keys++; /* HvKEYS(hv)++ */ + xhv->xhv_keys++; /* HvTOTALKEYS(hv)++ */ if (!next) { /* initial entry? */ xhv->xhv_fill++; /* HvFILL(hv)++ */ } else if (xhv->xhv_keys > (IV)xhv->xhv_max /* HvKEYS(hv) > HvMAX(hv) */) { @@ -2451,7 +2502,7 @@ S_share_hek_flags(pTHX_ const char *str, I32 len, register U32 hash, int flags) } } - ++HeVAL(entry); /* use value slot as REFCNT */ + ++entry->he_valu.hent_refcount; UNLOCK_STRTAB_MUTEX; if (flags & HVhek_FREEKEY) @@ -2502,6 +2553,256 @@ Perl_hv_placeholders_set(pTHX_ HV *hv, I32 ph) } /* +=for apidoc refcounted_he_chain_2hv + +Generates an returns a C by walking up the tree starting at the passed +in C. + +=cut +*/ +HV * +Perl_refcounted_he_chain_2hv(pTHX_ const struct refcounted_he *chain) +{ + HV *hv = newHV(); + U32 placeholders = 0; + /* We could chase the chain once to get an idea of the number of keys, + and call ksplit. But for now we'll make a potentially inefficient + hash with only 8 entries in its array. */ + const U32 max = HvMAX(hv); + + if (!HvARRAY(hv)) { + char *array; + Newxz(array, PERL_HV_ARRAY_ALLOC_BYTES(max + 1), char); + HvARRAY(hv) = (HE**)array; + } + + while (chain) { +#ifdef USE_ITHREADS + U32 hash = chain->refcounted_he_hash; +#else + U32 hash = HEK_HASH(chain->refcounted_he_hek); +#endif + HE **oentry = &((HvARRAY(hv))[hash & max]); + HE *entry = *oentry; + SV *value; + + for (; entry; entry = HeNEXT(entry)) { + if (HeHASH(entry) == hash) { + goto next_please; + } + } + assert (!entry); + entry = new_HE(); + +#ifdef USE_ITHREADS + HeKEY_hek(entry) + = share_hek_flags(/* A big expression to find the key offset */ + (((chain->refcounted_he_data[0] + & HVrhek_typemask) == HVrhek_PV) + ? chain->refcounted_he_val.refcounted_he_u_len + + 1 : 0) + 1 + chain->refcounted_he_data, + chain->refcounted_he_keylen, + chain->refcounted_he_hash, + (chain->refcounted_he_data[0] + & (HVhek_UTF8|HVhek_WASUTF8))); +#else + HeKEY_hek(entry) = share_hek_hek(chain->refcounted_he_hek); +#endif + + switch(chain->refcounted_he_data[0] & HVrhek_typemask) { + case HVrhek_undef: + value = newSV(0); + break; + case HVrhek_delete: + value = &PL_sv_placeholder; + placeholders++; + break; + case HVrhek_IV: + value = (chain->refcounted_he_data[0] & HVrhek_UV) + ? newSViv(chain->refcounted_he_val.refcounted_he_u_iv) + : newSViv(chain->refcounted_he_val.refcounted_he_u_uv); + break; + case HVrhek_PV: + /* Create a string SV that directly points to the bytes in our + structure. */ + value = newSV(0); + sv_upgrade(value, SVt_PV); + SvPV_set(value, (char *) chain->refcounted_he_data + 1); + SvCUR_set(value, chain->refcounted_he_val.refcounted_he_u_len); + /* This stops anything trying to free it */ + SvLEN_set(value, 0); + SvPOK_on(value); + SvREADONLY_on(value); + if (chain->refcounted_he_data[0] & HVrhek_UTF8) + SvUTF8_on(value); + break; + default: + Perl_croak(aTHX_ "panic: refcounted_he_chain_2hv bad flags %x", + chain->refcounted_he_data[0]); + } + HeVAL(entry) = value; + + /* Link it into the chain. */ + HeNEXT(entry) = *oentry; + if (!HeNEXT(entry)) { + /* initial entry. */ + HvFILL(hv)++; + } + *oentry = entry; + + HvTOTALKEYS(hv)++; + + next_please: + chain = chain->refcounted_he_next; + } + + if (placeholders) { + clear_placeholders(hv, placeholders); + HvTOTALKEYS(hv) -= placeholders; + } + + /* We could check in the loop to see if we encounter any keys with key + flags, but it's probably not worth it, as this per-hash flag is only + really meant as an optimisation for things like Storable. */ + HvHASKFLAGS_on(hv); + DEBUG_A(Perl_hv_assert(aTHX_ hv)); + + return hv; +} + +/* +=for apidoc refcounted_he_new + +Creates a new C. Assumes ownership of one reference +to I. As S is copied into a shared hash key, all references remain +the property of the caller. The C is returned with a +reference count of 1. + +=cut +*/ + +struct refcounted_he * +Perl_refcounted_he_new(pTHX_ struct refcounted_he *const parent, + SV *const key, SV *const value) { + struct refcounted_he *he; + STRLEN key_len; + const char *key_p = SvPV_const(key, key_len); + STRLEN value_len = 0; + const char *value_p; + char value_type; + char flags; + STRLEN key_offset; + U32 hash; + bool is_utf8 = SvUTF8(key); + + if (SvPOK(value)) { + value_type = HVrhek_PV; + } else if (SvIOK(value)) { + value_type = HVrhek_IV; + } else if (value == &PL_sv_placeholder) { + value_type = HVrhek_delete; + } else if (!SvOK(value)) { + value_type = HVrhek_undef; + } else { + value_type = HVrhek_PV; + } + + if (value_type == HVrhek_PV) { + value_p = SvPV_const(value, value_len); + key_offset = value_len + 2; + } else { + value_len = 0; + key_offset = 1; + } + flags = value_type; + + he = PerlMemShared_malloc(sizeof(struct refcounted_he) - 1 +#ifdef USE_ITHREADS + + key_len +#endif + + key_offset); + + + he->refcounted_he_next = parent; + + if (value_type == HVrhek_PV) { + Copy(value_p, he->refcounted_he_data + 1, value_len + 1, char); + he->refcounted_he_val.refcounted_he_u_len = value_len; + if (SvUTF8(value)) { + flags |= HVrhek_UTF8; + } + } else if (value_type == HVrhek_IV) { + if (SvUOK(value)) { + he->refcounted_he_val.refcounted_he_u_uv = SvUVX(value); + flags |= HVrhek_UV; + } else { + he->refcounted_he_val.refcounted_he_u_iv = SvIVX(value); + } + } + + if (is_utf8) { + /* Hash keys are always stored normalised to (yes) ISO-8859-1. + As we're going to be building hash keys from this value in future, + normalise it now. */ + key_p = (char*)bytes_from_utf8((const U8*)key_p, &key_len, &is_utf8); + flags |= is_utf8 ? HVhek_UTF8 : HVhek_WASUTF8; + } + PERL_HASH(hash, key_p, key_len); + +#ifdef USE_ITHREADS + he->refcounted_he_hash = hash; + he->refcounted_he_keylen = key_len; + Copy(key_p, he->refcounted_he_data + key_offset, key_len, char); +#else + he->refcounted_he_hek = share_hek_flags(key_p, key_len, hash, flags); +#endif + + if (flags & HVhek_WASUTF8) { + /* If it was downgraded from UTF-8, then the pointer returned from + bytes_from_utf8 is an allocated pointer that we must free. */ + Safefree(key_p); + } + + he->refcounted_he_data[0] = flags; + he->refcounted_he_refcnt = 1; + + return he; +} + +/* +=for apidoc refcounted_he_free + +Decrements the reference count of the passed in C +by one. If the reference count reaches zero the structure's memory is freed, +and C iterates onto the parent node. + +=cut +*/ + +void +Perl_refcounted_he_free(pTHX_ struct refcounted_he *he) { + while (he) { + struct refcounted_he *copy; + U32 new_count; + + HINTS_REFCNT_LOCK; + new_count = --he->refcounted_he_refcnt; + HINTS_REFCNT_UNLOCK; + + if (new_count) { + return; + } + +#ifndef USE_ITHREADS + unshare_hek_or_pvn (he->refcounted_he_hek, 0, 0, 0); +#endif + copy = he; + he = he->refcounted_he_next; + PerlMemShared_free(copy); + } +} + +/* =for apidoc hv_assert Check that a hash is in an internally consistent state. @@ -2509,6 +2810,8 @@ Check that a hash is in an internally consistent state. =cut */ +#ifdef DEBUGGING + void Perl_hv_assert(pTHX_ HV *hv) { @@ -2532,7 +2835,7 @@ Perl_hv_assert(pTHX_ HV *hv) } /* sanity check the keys */ if (HeSVKEY(entry)) { - /* Don't know what to check on SV keys. */ + /*EMPTY*/ /* Don't know what to check on SV keys. */ } else if (HeKUTF8(entry)) { withflags++; if (HeKWASUTF8(entry)) { @@ -2571,6 +2874,8 @@ Perl_hv_assert(pTHX_ HV *hv) HvEITER_set(hv, eiter); } +#endif + /* * Local variables: * c-indentation-style: bsd