}
#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)
{
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));
/* 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;
}
/* 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;
case PERL_MAGIC_tied:
case PERL_MAGIC_sig:
*needs_store = FALSE;
+ return; /* We've set all there is to set. */
}
}
mg = mg->mg_moremagic;
/*PerlIO_printf(PerlIO_stderr(), "hsplit called for %p which had %d\n",
hv, (int) oldsize);*/
- if (HvPLACEHOLDERS(hv) && !SvREADONLY(hv)) {
+ if (HvPLACEHOLDERS_get(hv) && !SvREADONLY(hv)) {
/* Can make this clear any placeholders first for non-restricted hashes,
even though Storable rebuilds restricted hashes by putting in all the
placeholders (first) before turning on the readonly flag, because
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;
Perl_hv_clear_placeholders(pTHX_ HV *hv)
{
dVAR;
- I32 items = (I32)HvPLACEHOLDERS(hv);
+ I32 items = (I32)HvPLACEHOLDERS_get(hv);
I32 i = HvMAX(hv);
if (items == 0)
if (--items == 0) {
/* Finished. */
- HvTOTALKEYS(hv) -= (IV)HvPLACEHOLDERS(hv);
+ HvTOTALKEYS(hv) -= (IV)HvPLACEHOLDERS_get(hv);
if (HvKEYS(hv) == 0)
HvHASKFLAGS_off(hv);
- HvPLACEHOLDERS(hv) = 0;
+ HvPLACEHOLDERS_set(hv, 0);
return;
}
} else {
HvLAZYDEL_off(hv);
hv_free_ent(hv, entry);
}
+ if (iter->xhv_name)
+ unshare_hek_or_pvn(iter->xhv_name, 0, 0, 0);
Safefree(iter);
((XPVHV*) SvANY(hv))->xhv_aux = 0;
}
hfreeentries(hv);
Safefree(HvARRAY(hv));
if ((name = HvNAME_get(hv))) {
- /* FIXME - strlen HvNAME */
if(PL_stashcache)
- hv_delete(PL_stashcache, name, strlen(name), G_DISCARD);
+ hv_delete(PL_stashcache, name, HvNAMELEN_get(hv), G_DISCARD);
Perl_hv_name_set(aTHX_ hv, 0, 0, 0);
}
xhv->xhv_max = 7; /* HvMAX(hv) = 7 (it's a normal hash) */
}
/* used to be xhv->xhv_fill before 5.004_65 */
- return XHvTOTALKEYS(xhv);
+ return HvTOTALKEYS(hv);
}
I32 *
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)
+Perl_hv_name_set(pTHX_ HV *hv, const char *name, I32 len, int flags)
{
struct xpvhv_aux *iter = ((XPVHV *)SvANY(hv))->xhv_aux;
+ U32 hash;
- if (!iter) {
+ if (iter) {
+ if (iter->xhv_name) {
+ unshare_hek_or_pvn(iter->xhv_name, 0, 0, 0);
+ }
+ } else {
if (name == 0)
return;
((XPVHV *)SvANY(hv))->xhv_aux = iter = S_hv_auxinit(aTHX);
}
- iter->xhv_name = savepvn(name, len);
+ PERL_HASH(hash, name, len);
+ iter->xhv_name = name ? share_hek(name, len, hash) : 0;
}
/*
register XPVHV* xhv;
register HE *entry;
register HE **oentry;
- register I32 i = 1;
+ HE **first;
bool found = 0;
bool is_utf8 = FALSE;
int k_flags = 0;
xhv = (XPVHV*)SvANY(PL_strtab);
/* assert(xhv_array != 0) */
LOCK_STRTAB_MUTEX;
- oentry = &(HvARRAY(PL_strtab))[hash & (I32) HvMAX(PL_strtab)];
+ first = oentry = &(HvARRAY(PL_strtab))[hash & (I32) HvMAX(PL_strtab)];
if (hek) {
- for (entry = *oentry; entry; i=0, oentry = &HeNEXT(entry), entry = *oentry) {
+ for (entry = *oentry; entry; oentry = &HeNEXT(entry), entry = *oentry) {
if (HeKEY_hek(entry) != hek)
continue;
found = 1;
}
} else {
const int flags_masked = k_flags & HVhek_MASK;
- for (entry = *oentry; entry; i=0, oentry = &HeNEXT(entry), entry = *oentry) {
+ for (entry = *oentry; entry; oentry = &HeNEXT(entry), entry = *oentry) {
if (HeHASH(entry) != hash) /* strings can't be equal */
continue;
if (HeKLEN(entry) != len)
if (found) {
if (--HeVAL(entry) == Nullsv) {
*oentry = HeNEXT(entry);
- if (i && !*oentry)
+ if (!*first) {
+ /* There are now no entries in our slot. */
xhv->xhv_fill--; /* HvFILL(hv)-- */
+ }
Safefree(HeKEY_hek(entry));
del_HE(entry);
xhv->xhv_keys--; /* HvKEYS(hv)-- */
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;
register HE *entry;
register HE **oentry;
- register I32 i = 1;
I32 found = 0;
const int flags_masked = flags & HVhek_MASK;
/* assert(xhv_array != 0) */
LOCK_STRTAB_MUTEX;
oentry = &(HvARRAY(PL_strtab))[hash & (I32) HvMAX(PL_strtab)];
- for (entry = *oentry; entry; i=0, entry = HeNEXT(entry)) {
+ for (entry = *oentry; entry; entry = HeNEXT(entry)) {
if (HeHASH(entry) != hash) /* strings can't be equal */
continue;
if (HeKLEN(entry) != len)
break;
}
if (!found) {
+ /* What used to be head of the list.
+ If this is NULL, then we're the first entry for this slot, which
+ means we need to increate fill. */
+ const HE *old_first = *oentry;
entry = new_HE();
HeKEY_hek(entry) = save_hek_flags(str, len, hash, flags_masked);
HeVAL(entry) = Nullsv;
HeNEXT(entry) = *oentry;
*oentry = entry;
xhv->xhv_keys++; /* HvKEYS(hv)++ */
- if (i) { /* initial entry? */
+ if (!old_first) { /* initial entry? */
xhv->xhv_fill++; /* HvFILL(hv)++ */
} else if (xhv->xhv_keys > (IV)xhv->xhv_max /* HvKEYS(hv) > HvMAX(hv) */) {
hsplit(PL_strtab);
if (flags & HVhek_FREEKEY)
Safefree(str);
- return HeKEY_hek(entry);
+ return entry;
}
I32 *
(int) real, (int) HvUSEDKEYS(hv));
bad = 1;
}
- if (HvPLACEHOLDERS(hv) != placeholders) {
+ if (HvPLACEHOLDERS_get(hv) != placeholders) {
PerlIO_printf(Perl_debug_log,
"Count %d placeholder(s), but hash reports %d\n",
- (int) placeholders, (int) HvPLACEHOLDERS(hv));
+ (int) placeholders, (int) HvPLACEHOLDERS_get(hv));
bad = 1;
}
}