hash keys to save repeated lookups during cloning.
p4raw-id: //depot/perl@24574
s |HEK* |save_hek_flags |const char *str|I32 len|U32 hash|int flags
s |void |hv_magic_check |HV *hv|bool *needs_copy|bool *needs_store
s |void |unshare_hek_or_pvn|HEK* hek|const char* sv|I32 len|U32 hash
-s |HEK* |share_hek_flags|const char* sv|I32 len|U32 hash|int flags
+s |HE* |share_hek_flags|const char* sv|I32 len|U32 hash|int flags
rs |void |hv_notallowed |int flags|const char *key|I32 klen|const char *msg
#endif
#define PL_savebegin (vTHX->Isavebegin)
#define PL_sawampersand (vTHX->Isawampersand)
#define PL_sh_path_compat (vTHX->Ish_path_compat)
+#define PL_shared_hek_table (vTHX->Ishared_hek_table)
#define PL_sharehook (vTHX->Isharehook)
#define PL_sig_pending (vTHX->Isig_pending)
#define PL_sighandlerp (vTHX->Isighandlerp)
#define PL_Isavebegin PL_savebegin
#define PL_Isawampersand PL_sawampersand
#define PL_Ish_path_compat PL_sh_path_compat
+#define PL_Ishared_hek_table PL_shared_hek_table
#define PL_Isharehook PL_sharehook
#define PL_Isig_pending PL_sig_pending
#define PL_Isighandlerp PL_sighandlerp
clone_params.stashes = newAV();
clone_params.flags |= CLONEf_JOIN_IN;
PL_ptr_table = ptr_table_new();
+ PL_shared_hek_table = ptr_table_new();
current_thread = Perl_ithread_get(aTHX);
Perl_ithread_set(aTHX_ thread);
/* ensure 'meaningful' addresses retain their meaning */
SvREFCNT_inc(retparam);
ptr_table_free(PL_ptr_table);
PL_ptr_table = NULL;
+ ptr_table_free(PL_shared_hek_table);
+ PL_shared_hek_table = NULL;
}
/* We are finished with it */
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) {
+ 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;
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;
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;
if (flags & HVhek_FREEKEY)
Safefree(str);
- return HeKEY_hek(entry);
+ return entry;
}
I32 *
#if defined(USE_ITHREADS)
PERLVAR(Iptr_table, PTR_TBL_t*)
+PERLVAR(Ishared_hek_table, PTR_TBL_t*)
#endif
PERLVARI(Ibeginav_save, AV*, Nullav) /* save BEGIN{}s when compiling */
SvREFCNT_dec(PL_strtab);
#ifdef USE_ITHREADS
- /* free the pointer table used for cloning */
+ /* free the pointer tables used for cloning */
ptr_table_free(PL_ptr_table);
PL_ptr_table = (PTR_TBL_t*)NULL;
+ ptr_table_free(PL_shared_hek_table);
+ PL_shared_hek_table = (PTR_TBL_t*)NULL;
#endif
/* free special SVs */
#define PL_sawampersand (*Perl_Isawampersand_ptr(aTHX))
#undef PL_sh_path_compat
#define PL_sh_path_compat (*Perl_Ish_path_compat_ptr(aTHX))
+#undef PL_shared_hek_table
+#define PL_shared_hek_table (*Perl_Ishared_hek_table_ptr(aTHX))
#undef PL_sharehook
#define PL_sharehook (*Perl_Isharehook_ptr(aTHX))
#undef PL_sig_pending
STATIC HEK* S_save_hek_flags(pTHX_ const char *str, I32 len, U32 hash, int flags);
STATIC void S_hv_magic_check(pTHX_ HV *hv, bool *needs_copy, bool *needs_store);
STATIC void S_unshare_hek_or_pvn(pTHX_ HEK* hek, const char* sv, I32 len, U32 hash);
-STATIC HEK* S_share_hek_flags(pTHX_ const char* sv, I32 len, U32 hash, int flags);
+STATIC HE* S_share_hek_flags(pTHX_ const char* sv, I32 len, U32 hash, int flags);
STATIC void S_hv_notallowed(pTHX_ int flags, const char *key, I32 klen, const char *msg)
__attribute__noreturn__;
/* create SV map for pointer relocation */
PL_ptr_table = ptr_table_new();
+ /* and one for finding shared hash keys quickly */
+ PL_shared_hek_table = ptr_table_new();
/* initialize these special pointers as early as possible */
SvANY(&PL_sv_undef) = NULL;
if (!(flags & CLONEf_KEEP_PTR_TABLE)) {
ptr_table_free(PL_ptr_table);
PL_ptr_table = NULL;
+ ptr_table_free(PL_shared_hek_table);
+ PL_shared_hek_table = NULL;
}
/* Call the ->CLONE method, if it exists, for each of the stashes