fix Embed.t failure on windows: PERL_SYS_TERM() is implemented
[p5sagit/p5-mst-13.2.git] / pad.c
diff --git a/pad.c b/pad.c
index e1ac067..3856b47 100644 (file)
--- a/pad.c
+++ b/pad.c
@@ -1,6 +1,6 @@
 /*    pad.c
  *
- *    Copyright (c) 2002, Larry Wall
+ *    Copyright (C) 2002, by Larry Wall and others
  *
  *    You may distribute under the terms of either the GNU General Public
  *    License or the Artistic License, as specified in the README file.
@@ -46,9 +46,9 @@ The 0'th slot of a frame AV is an AV which is @_.
 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.
@@ -78,7 +78,7 @@ a REFCNT'ed references to a lexical from "outside". In this case,
 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.)
@@ -111,7 +111,7 @@ can be OR'ed together:
 */
 
 PADLIST *
-Perl_pad_new(pTHX_ padnew_flags flags)
+Perl_pad_new(pTHX_ int flags)
 {
     AV *padlist, *padname, *pad, *a0;
 
@@ -198,6 +198,9 @@ PL_*pad* global vars so that we don't have any dangling references left.
 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
 */
 
@@ -216,16 +219,15 @@ Perl_pad_undef(pTHX_ CV* cv)
          "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];
@@ -233,25 +235,26 @@ Perl_pad_undef(pTHX_ CV* cv)
        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--];
@@ -375,9 +378,7 @@ Perl_pad_alloc(pTHX_ I32 optype, U32 tmptype)
     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 {
@@ -434,6 +435,14 @@ Perl_pad_add_anon(pTHX_ SV* sv, OPCODE op_type)
     /* 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;
 }
 
@@ -543,13 +552,8 @@ Perl_pad_findmy(pTHX_ char *name)
            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;
        }
     }
@@ -611,6 +615,8 @@ S_pad_findlex(pTHX_ char *name, PADOFFSET newoff, CV* innercv)
        );
 
        curlist = CvPADLIST(cv);
+       if (!curlist)
+           continue; /* an undef CV */
        svp = av_fetch(curlist, 0, FALSE);
        if (!svp || *svp == &PL_sv_undef)
            continue;
@@ -903,7 +909,7 @@ Perl_pad_leavemy(pTHX)
            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. */
@@ -1107,13 +1113,15 @@ Perl_pad_free(pTHX_ PADOFFSET po)
     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)
@@ -1277,7 +1285,7 @@ S_cv_clone2(pTHX_ CV *proto, CV *outside)
 
     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
@@ -1329,8 +1337,7 @@ S_cv_clone2(pTHX_ CV *proto, CV *outside)
                    sv = (SV*)newHV();
                else
                    sv = NEWSV(0, 0);
-               if (!SvPADBUSY(sv))
-                   SvPADMY_on(sv);
+               SvPADMY_on(sv);
                PL_curpad[ix] = sv;
            }
        }
@@ -1359,6 +1366,9 @@ S_cv_clone2(pTHX_ CV *proto, CV *outside)
            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);
        }
     }
 
@@ -1387,7 +1397,8 @@ S_cv_clone2(pTHX_ CV *proto, CV *outside)
 =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
 */
@@ -1406,18 +1417,14 @@ Perl_pad_fixup_inner_anons(pTHX_ PADLIST *padlist, CV *old_cv, CV *new_cv)
            && *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