Ap |void |hv_name_set |NN HV *hv|NULLOK const char *name|U32 len|U32 flags
: Used in dump.c and hv.c
poM |AV** |hv_backreferences_p |NN HV *hv
-#if defined(PERL_IN_DUMP_C) || defined(PERL_IN_HV_C) || defined(PERL_IN_SV_C)
-: Only used in sv.c
-poM |void |hv_kill_backrefs |NN HV *hv
-#endif
Apd |void |hv_clear_placeholders |NN HV *hv
ApoR |I32* |hv_placeholders_p |NN HV *hv
ApoR |I32 |hv_placeholders_get |NN const HV *hv
#endif
#define hv_scalar Perl_hv_scalar
#define hv_name_set Perl_hv_name_set
-#if defined(PERL_IN_DUMP_C) || defined(PERL_IN_HV_C) || defined(PERL_IN_SV_C)
-#endif
#define hv_clear_placeholders Perl_hv_clear_placeholders
#ifdef PERL_CORE
#define magic_scalarpack Perl_magic_scalarpack
#define hv_name_set(a,b,c,d) Perl_hv_name_set(aTHX_ a,b,c,d)
#ifdef PERL_CORE
#endif
-#if defined(PERL_IN_DUMP_C) || defined(PERL_IN_HV_C) || defined(PERL_IN_SV_C)
-#ifdef PERL_CORE
-#endif
-#endif
#define hv_clear_placeholders(a) Perl_hv_clear_placeholders(aTHX_ a)
#ifdef PERL_CORE
#define magic_scalarpack(a,b) Perl_magic_scalarpack(aTHX_ a,b)
if (SvOOK(hv)) {
HE *entry;
struct mro_meta *meta;
- struct xpvhv_aux *iter = HvAUX(hv);
- /* If there are weak references to this HV, we need to avoid
- freeing them up here. In particular we need to keep the AV
- visible as what we're deleting might well have weak references
- back to this HV, so the for loop below may well trigger
- the removal of backreferences from this array. */
-
- if (iter->xhv_backreferences) {
- /* So donate them to regular backref magic to keep them safe.
- The sv_magic will increase the reference count of the AV,
- so we need to drop it first. */
- SvREFCNT_dec(iter->xhv_backreferences);
- if (AvFILLp(iter->xhv_backreferences) == -1) {
- /* Turns out that the array is empty. Just free it. */
- SvREFCNT_dec(iter->xhv_backreferences);
+ struct xpvhv_aux * const iter = HvAUX(hv);
+ SV *const av = iter->xhv_backreferences;
- } else {
- sv_magic(MUTABLE_SV(hv),
- MUTABLE_SV(iter->xhv_backreferences),
- PERL_MAGIC_backref, NULL, 0);
- }
- iter->xhv_backreferences = NULL;
+ if (av) {
+ Perl_sv_kill_backrefs(aTHX_ MUTABLE_SV(hv), av);
+ SvREFCNT_dec(av);
+ iter->xhv_backreferences = 0;
}
entry = iter->xhv_eiter; /* HvEITER(hv) */
}
/* make everyone else think the array is empty, so that the destructors
- * called for freed entries can't recusively mess with us */
+ * called for freed entries can't recursively mess with us */
HvARRAY(hv) = NULL;
((XPVHV*) SvANY(hv))->xhv_keys = 0;
return &(iter->xhv_backreferences);
}
-void
-Perl_hv_kill_backrefs(pTHX_ HV *hv) {
- AV *av;
-
- PERL_ARGS_ASSERT_HV_KILL_BACKREFS;
-
- if (!SvOOK(hv))
- return;
-
- av = HvAUX(hv)->xhv_backreferences;
-
- if (av) {
- HvAUX(hv)->xhv_backreferences = 0;
- Perl_sv_kill_backrefs(aTHX_ MUTABLE_SV(hv), av);
- SvREFCNT_dec(av);
- }
-}
-
/*
hv_iternext is implemented as a macro in hv.h
#define PERL_ARGS_ASSERT_HV_BACKREFERENCES_P \
assert(hv)
-#if defined(PERL_IN_DUMP_C) || defined(PERL_IN_HV_C) || defined(PERL_IN_SV_C)
-PERL_CALLCONV void Perl_hv_kill_backrefs(pTHX_ HV *hv)
- __attribute__nonnull__(pTHX_1);
-#define PERL_ARGS_ASSERT_HV_KILL_BACKREFS \
- assert(hv)
-
-#endif
PERL_CALLCONV void Perl_hv_clear_placeholders(pTHX_ HV *hv)
__attribute__nonnull__(pTHX_1);
#define PERL_ARGS_ASSERT_HV_CLEAR_PLACEHOLDERS \
/* A discussion about the backreferences array and its refcount:
*
* The AV holding the backreferences is pointed to either as the mg_obj of
- * PERL_MAGIC_backref, or in the specific case of a HV that has the hv_aux
- * structure, from the xhv_backreferences field. (A HV without hv_aux will
- * have the standard magic instead.) The array is created with a refcount
- * of 2. This means that if during global destruction the array gets
- * picked on first to have its refcount decremented by the random zapper,
- * it won't actually be freed, meaning it's still theere for when its
- * parent gets freed.
+ * PERL_MAGIC_backref, or in the specific case of a HV, from the
+ * xhv_backreferences field of the HvAUX structure. The array is created
+ * with a refcount of 2. This means that if during global destruction the
+ * array gets picked on before its parent to have its refcount decremented
+ * by the random zapper, it won't actually be freed, meaning it's still
+ * there for when its parent gets freed.
* When the parent SV is freed, in the case of magic, the magic is freed,
* Perl_magic_killbackrefs is called which decrements one refcount, then
* mg_obj is freed which kills the second count.
- * In the vase of a HV being freed, one ref is removed by
- * Perl_hv_kill_backrefs, the other by Perl_sv_kill_backrefs, which it
- * calls.
+ * In the vase of a HV being freed, one ref is removed by S_hfreeentries,
+ * the other by Perl_sv_kill_backrefs, which it calls.
*/
void
av = *avp;
if (!av) {
- /* There is no AV in the offical place - try a fixup. */
- MAGIC *const mg = mg_find(tsv, PERL_MAGIC_backref);
-
- if (mg) {
- /* Aha. They've got it stowed in magic. Bring it back. */
- av = MUTABLE_AV(mg->mg_obj);
- /* Stop mg_free decreasing the refernce count. */
- mg->mg_obj = NULL;
- /* Stop mg_free even calling the destructor, given that
- there's no AV to free up. */
- mg->mg_virtual = 0;
- sv_unmagic(tsv, PERL_MAGIC_backref);
- } else {
- av = newAV();
- AvREAL_off(av);
- SvREFCNT_inc_simple_void(av); /* see discussion above */
- }
+ av = newAV();
+ AvREAL_off(av);
+ SvREFCNT_inc_simple_void(av); /* see discussion above */
*avp = av;
}
} else {
PERL_ARGS_ASSERT_SV_KILL_BACKREFS;
PERL_UNUSED_ARG(sv);
- assert(!svp || !SvIS_FREED(av));
if (svp) {
SV *const *const last = svp + AvFILLp(av);
+ assert(!SvIS_FREED(av));
while (svp <= last) {
if (*svp) {
SV *const referrer = *svp;
}
svp++;
}
+ AvFILLp(av) = -1;
}
SvREFCNT_dec(av); /* remove extra count added by sv_add_backref() */
return 0;
if (PL_last_swash_hv == (const HV *)sv) {
PL_last_swash_hv = NULL;
}
- Perl_hv_kill_backrefs(aTHX_ MUTABLE_HV(sv));
hv_undef(MUTABLE_HV(sv));
break;
case SVt_PVAV: