/* pad.c
*
- * Copyright (c) 2002, Larry Wall
+ * Copyright (c) 2003, Larry Wall
*
* You may distribute under the terms of either the GNU General Public
* License or the Artistic License, as specified in the README file.
other entries are storage for variables and op targets.
During compilation:
-C<PL_comppad_name> is set the the the names AV.
-C<PL_comppad> is set the the frame AV for the frame CvDEPTH == 1.
-C<PL_curpad> is set the body of the frame AV (i.e. AvARRAY(PL_comppad)).
+C<PL_comppad_name> is set to the names AV.
+C<PL_comppad> is set to the frame AV for the frame CvDEPTH == 1.
+C<PL_curpad> is set to the body of the frame AV (i.e. AvARRAY(PL_comppad)).
During execution, C<PL_comppad> and C<PL_curpad> refer to the live
frame of the currently executing sub.
the name SV does not have a cop_seq range, since it is in scope
throughout.
-If the 'name' is '&' the the corresponding entry in frame AV
+If the 'name' is '&' the corresponding entry in frame AV
is a CV representing a possible closure.
(SvFAKE and name of '&' is not a meaningful combination currently but could
become so if C<my sub foo {}> is implemented.)
*/
PADLIST *
-Perl_pad_new(pTHX_ padnew_flags flags)
+Perl_pad_new(pTHX_ int flags)
{
AV *padlist, *padname, *pad, *a0;
We also repoint the CvOUTSIDE of any about-to-be-orphaned
inner subs to the outer of this cv.
+(This function should really be called pad_free, but the name was already
+taken)
+
=cut
*/
"Pad undef: padlist=0x%"UVxf"\n" , PTR2UV(padlist))
);
- /* pads may be cleared out already during global destruction */
- if ((CvEVAL(cv) && !CvGV(cv) /* is this eval"" ? */
- && !PL_dirty) || CvSPECIAL(cv))
- {
- CV *outercv = CvOUTSIDE(cv);
- U32 seq = CvOUTSIDE_SEQ(cv);
- /* XXX DAPM the following code is very similar to
- * pad_fixup_inner_anons(). Merge??? */
+ /* detach any '&' anon children in the pad; if afterwards they
+ * are still live, fix up their CvOUTSIDEs to point to our outside,
+ * bypassing us. */
+ /* XXX DAPM for efficiency, we should only do this if we know we have
+ * children, or integrate this loop with general cleanup */
- /* inner references to eval's/BEGIN's/etc cv must be fixed up */
+ if (!PL_dirty) { /* don't bother during global destruction */
+ CV *outercv = CvOUTSIDE(cv);
+ U32 seq = CvOUTSIDE_SEQ(cv);
AV *comppad_name = (AV*)AvARRAY(padlist)[0];
SV **namepad = AvARRAY(comppad_name);
AV *comppad = (AV*)AvARRAY(padlist)[1];
for (ix = AvFILLp(comppad_name); ix > 0; ix--) {
SV *namesv = namepad[ix];
if (namesv && namesv != &PL_sv_undef
- && *SvPVX(namesv) == '&'
- && ix <= AvFILLp(comppad))
+ && *SvPVX(namesv) == '&')
{
CV *innercv = (CV*)curpad[ix];
- if (innercv && SvTYPE(innercv) == SVt_PVCV
+ namepad[ix] = Nullsv;
+ SvREFCNT_dec(namesv);
+ curpad[ix] = Nullsv;
+ SvREFCNT_dec(innercv);
+ if (SvREFCNT(innercv) /* in use, not just a prototype */
&& CvOUTSIDE(innercv) == cv)
{
+ assert(CvWEAKOUTSIDE(innercv));
+ CvWEAKOUTSIDE_off(innercv);
CvOUTSIDE(innercv) = outercv;
CvOUTSIDE_SEQ(innercv) = seq;
- /* anon prototypes aren't refcounted */
- if (!CvANON(innercv) || CvCLONED(innercv)) {
- (void)SvREFCNT_inc(outercv);
- if (SvREFCNT(cv))
- SvREFCNT_dec(cv);
- }
+ SvREFCNT_inc(outercv);
}
}
}
}
+
ix = AvFILLp(padlist);
while (ix >= 0) {
SV* sv = AvARRAY(padlist)[ix--];
if (PL_pad_reset_pending)
pad_reset();
if (tmptype & SVs_PADMY) {
- do {
- sv = *av_fetch(PL_comppad, AvFILLp(PL_comppad) + 1, TRUE);
- } while (SvPADBUSY(sv)); /* need a fresh one */
+ sv = *av_fetch(PL_comppad, AvFILLp(PL_comppad) + 1, TRUE);
retval = AvFILLp(PL_comppad);
}
else {
/* XXX DAPM use PL_curpad[] ? */
av_store(PL_comppad, ix, sv);
SvPADMY_on(sv);
+
+ /* to avoid ref loops, we never have parent + child referencing each
+ * other simultaneously */
+ if (CvOUTSIDE((CV*)sv)) {
+ assert(!CvWEAKOUTSIDE((CV*)sv));
+ CvWEAKOUTSIDE_on((CV*)sv);
+ SvREFCNT_dec(CvOUTSIDE((CV*)sv));
+ }
return ix;
}
continue;
}
else {
- if (
- ( seq > (U32)I_32(SvNVX(sv)) /* min */
- && seq <= (U32)SvIVX(sv)) /* max */
- ||
- /* 'our' is visible before introduction */
- (!SvIVX(sv) && (SvFLAGS(sv) & SVpad_OUR))
- )
+ if ( seq > (U32)I_32(SvNVX(sv)) /* min */
+ && seq <= (U32)SvIVX(sv)) /* max */
return off;
}
}
);
curlist = CvPADLIST(cv);
+ if (!curlist)
+ continue; /* an undef CV */
svp = av_fetch(curlist, 0, FALSE);
if (!svp || *svp == &PL_sv_undef)
continue;
if ((sv = svp[off]) && sv != &PL_sv_undef
&& !SvFAKE(sv) && ckWARN_d(WARN_INTERNAL))
Perl_warner(aTHX_ packWARN(WARN_INTERNAL),
- "%s never introduced", SvPVX(sv));
+ "%"SVf" never introduced", sv);
}
}
/* "Deintroduce" my variables that are leaving with this scope. */
if (PL_curpad[po] && PL_curpad[po] != &PL_sv_undef) {
SvPADTMP_off(PL_curpad[po]);
#ifdef USE_ITHREADS
+ /* SV could be a shared hash key (eg bugid #19022) */
+ if (
#ifdef PERL_COPY_ON_WRITE
- if (SvIsCOW(PL_curpad[po])) {
- sv_force_normal_flags(PL_curpad[po], SV_COW_DROP_PV);
- } else
+ !SvIsCOW(PL_curpad[po])
+#else
+ !SvFAKE(PL_curpad[po])
#endif
+ )
SvREADONLY_off(PL_curpad[po]); /* could be a freed constant */
-
#endif
}
if ((I32)po < PL_padix)
cv = PL_compcv = (CV*)NEWSV(1104, 0);
sv_upgrade((SV *)cv, SvTYPE(proto));
- CvFLAGS(cv) = CvFLAGS(proto) & ~CVf_CLONE;
+ CvFLAGS(cv) = CvFLAGS(proto) & ~(CVf_CLONE|CVf_WEAKOUTSIDE);
CvCLONED_on(cv);
#ifdef USE_ITHREADS
sv = (SV*)newHV();
else
sv = NEWSV(0, 0);
- if (!SvPADBUSY(sv))
- SvPADMY_on(sv);
+ SvPADMY_on(sv);
PL_curpad[ix] = sv;
}
}
CvCLONE_on(kid);
SvPADMY_on(kid);
PL_curpad[ix] = (SV*)kid;
+ /* '&' entry points to child, so child mustn't refcnt parent */
+ CvWEAKOUTSIDE_on(kid);
+ SvREFCNT_dec(cv);
}
}
=for apidoc pad_fixup_inner_anons
For any anon CVs in the pad, change CvOUTSIDE of that CV from
-old_cv to new_cv if necessary.
+old_cv to new_cv if necessary. Needed when a newly-compiled CV has to be
+moved to a pre-existing CV struct.
=cut
*/
&& *SvPVX(namesv) == '&')
{
CV *innercv = (CV*)curpad[ix];
- if (CvOUTSIDE(innercv) == old_cv) {
- CvOUTSIDE(innercv) = new_cv;
- /* anon prototypes aren't refcounted */
- if (!CvANON(innercv) || CvCLONED(innercv)) {
- (void)SvREFCNT_inc(new_cv);
- SvREFCNT_dec(old_cv);
- }
- }
+ assert(CvWEAKOUTSIDE(innercv));
+ assert(CvOUTSIDE(innercv) == old_cv);
+ CvOUTSIDE(innercv) = new_cv;
}
}
}
+
/*
=for apidoc pad_push