summaryrefslogtreecommitdiff
path: root/hv.c
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2010-07-29 17:56:24 +0100
committerDavid Mitchell <davem@iabyn.com>2010-07-29 17:56:24 +0100
commitcdb996f424d39d435ae0f0a024fbf20c38221b9e (patch)
tree9b277cc1fae33657e726e14c160755e95897282a /hv.c
parentcef0c2ea80abedd0fa6d0e228f3bf5b8bc3d2903 (diff)
downloadperl-cdb996f424d39d435ae0f0a024fbf20c38221b9e.tar.gz
expand the xhv_backreferences code notes
(so that I don't get so confused when I revisit this code in 5 years time)
Diffstat (limited to 'hv.c')
-rw-r--r--hv.c22
1 files changed, 15 insertions, 7 deletions
diff --git a/hv.c b/hv.c
index d7d6db1436..f110d15099 100644
--- a/hv.c
+++ b/hv.c
@@ -1666,15 +1666,23 @@ S_hfreeentries(pTHX_ HV *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. */
+ /* weak references: if called from sv_clear(), the backrefs
+ * should already have been killed; if there are any left, its
+ * because we're doing hv_clear() or hv_undef(), and the HV
+ * will continue to live.
+ * Because while freeing the entries we fake up a NULL HvARRAY
+ * (and hence HvAUX), we need to store the backref array
+ * somewhere else; but it still needs to be visible in case
+ * any the things we free happen to call sv_del_backref().
+ * We do this by storing it in magic instead.
+ * If, during the entry freeing, a destructor happens to add
+ * a new weak backref, then sv_add_backref will look in both
+ * places (magic in HvAUX) for the AV, but will create a new
+ * AV in HvAUX if it can't find one. So at the end of the
+ * iteration we have to allow for this. */
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,
+ /* 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) {