This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Eliminate PL_dirty
[perl5.git] / pad.c
diff --git a/pad.c b/pad.c
index 4d87758..1fcd375 100644 (file)
--- a/pad.c
+++ b/pad.c
@@ -1,16 +1,21 @@
 /*    pad.c
  *
- *    Copyright (C) 2002, 2003, 2004, 2005 by Larry Wall and others
+ *    Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ *    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.
+ */
+
+/*
+ *  'Anyway: there was this Mr. Frodo left an orphan and stranded, as you
+ *   might say, among those queer Bucklanders, being brought up anyhow in
+ *   Brandy Hall.  A regular warren, by all accounts.  Old Master Gorbadoc
+ *   never had fewer than a couple of hundred relations in the place.
+ *   Mr. Bilbo never did a kinder deed than when he brought the lad back
+ *   to live among decent folk.'                           --the Gaffer
  *
- *  "Anyway: there was this Mr Frodo left an orphan and stranded, as you
- *  might say, among those queer Bucklanders, being brought up anyhow in
- *  Brandy Hall. A regular warren, by all accounts. Old Master Gorbadoc
- *  never had fewer than a couple of hundred relations in the place. Mr
- *  Bilbo never did a kinder deed than when he brought the lad back to
- *  live among decent folk." --the Gaffer
+ *     [p.23 of _The Lord of the Rings_, I/i: "A Long-Expected Party"]
  */
 
 /* XXX DAPM
@@ -72,19 +77,19 @@ but only by their index allocated at compile time (which is usually
 in PL_op->op_targ), wasting a name SV for them doesn't make sense.
 
 The SVs in the names AV have their PV being the name of the variable.
-NV+1..IV inclusive is a range of cop_seq numbers for which the name is
-valid.  For typed lexicals name SV is SVt_PVMG and SvSTASH points at the
-type.  For C<our> lexicals, the type is SVt_PVGV, and GvSTASH points at the
-stash of the associated global (so that duplicate C<our> declarations in the
-same package can be detected).  SvCUR is sometimes hijacked to
-store the generation number during compilation.
+xlow+1..xhigh inclusive in the NV union is a range of cop_seq numbers for
+which the name is valid.  For typed lexicals name SV is SVt_PVMG and SvSTASH
+points at the type.  For C<our> lexicals, the type is also SVt_PVMG, with the
+SvOURSTASH slot pointing at the stash of the associated global (so that
+duplicate C<our> declarations in the same package can be detected).  SvUVX is
+sometimes hijacked to store the generation number during compilation.
 
 If SvFAKE is set on the name SV, then that slot in the frame AV is
 a REFCNT'ed reference to a lexical from "outside". In this case,
-the name SV does not use NVX and IVX to store a cop_seq range, since it is
-in scope throughout. Instead IVX stores some flags containing info about
+the name SV does not use xlow and xhigh to store a cop_seq range, since it is
+in scope throughout. Instead xhigh stores some flags containing info about
 the real lexical (is it declared in an anon, and is it capable of being
-instantiated multiple times?), and for fake ANONs, NVX contains the index
+instantiated multiple times?), and for fake ANONs, xlow contains the index
 within the parent's pad where the lexical's value is stored, to make
 cloning quicker.
 
@@ -96,12 +101,14 @@ become so if C<my sub foo {}> is implemented.)
 Note that formats are treated as anon subs, and are cloned each time
 write is called (if necessary).
 
-The flag SVf_PADSTALE is cleared on lexicals each time the my() is executed,
+The flag SVs_PADSTALE is cleared on lexicals each time the my() is executed,
 and set on scope exit. This allows the 'Variable $x is not available' warning
 to be generated in evals, such as 
 
     { my $x = 1; sub f { eval '$x'} } f();
 
+For state vars, SVs_PADSTALE is overloaded to mean 'not yet initialised'
+
 =cut
 */
 
@@ -109,11 +116,30 @@ to be generated in evals, such as
 #include "EXTERN.h"
 #define PERL_IN_PAD_C
 #include "perl.h"
+#include "keywords.h"
+
+#define COP_SEQ_RANGE_LOW_set(sv,val)          \
+  STMT_START { ((XPVNV*)SvANY(sv))->xnv_u.xpad_cop_seq.xlow = (val); } STMT_END
+#define COP_SEQ_RANGE_HIGH_set(sv,val)         \
+  STMT_START { ((XPVNV*)SvANY(sv))->xnv_u.xpad_cop_seq.xhigh = (val); } STMT_END
 
+#define PARENT_PAD_INDEX_set(sv,val)           \
+  STMT_START { ((XPVNV*)SvANY(sv))->xnv_u.xpad_cop_seq.xlow = (val); } STMT_END
+#define PARENT_FAKELEX_FLAGS_set(sv,val)       \
+  STMT_START { ((XPVNV*)SvANY(sv))->xnv_u.xpad_cop_seq.xhigh = (val); } STMT_END
 
-#define PAD_MAX 999999999
+#define PAD_MAX I32_MAX
 
+#ifdef PERL_MAD
+void pad_peg(const char* s) {
+    static int pegcnt; /* XXX not threadsafe */
+    PERL_UNUSED_ARG(s);
 
+    PERL_ARGS_ASSERT_PAD_PEG;
+
+    pegcnt++;
+}
+#endif
 
 /*
 =for apidoc pad_new
@@ -132,6 +158,7 @@ can be OR'ed together:
 PADLIST *
 Perl_pad_new(pTHX_ int flags)
 {
+    dVAR;
     AV *padlist, *padname, *pad;
 
     ASSERT_CURPAD_LEGAL("pad_new");
@@ -152,9 +179,9 @@ Perl_pad_new(pTHX_ int flags)
            SAVEI32(PL_comppad_name_fill);
            SAVEI32(PL_min_intro_pending);
            SAVEI32(PL_max_intro_pending);
-           SAVEI32(PL_cv_has_eval);
+           SAVEBOOL(PL_cv_has_eval);
            if (flags & padnew_SAVESUB) {
-               SAVEI32(PL_pad_reset_pending);
+               SAVEBOOL(PL_pad_reset_pending);
            }
        }
     }
@@ -174,22 +201,21 @@ Perl_pad_new(pTHX_ int flags)
         */
 
         AV * const a0 = newAV();                       /* will be @_ */
-       av_extend(a0, 0);
-       av_store(pad, 0, (SV*)a0);
+       av_store(pad, 0, MUTABLE_SV(a0));
        AvREIFY_only(a0);
     }
     else {
-       av_store(pad, 0, Nullsv);
+       av_store(pad, 0, NULL);
     }
 
     AvREAL_off(padlist);
-    av_store(padlist, 0, (SV*)padname);
-    av_store(padlist, 1, (SV*)pad);
+    av_store(padlist, 0, MUTABLE_SV(padname));
+    av_store(padlist, 1, MUTABLE_SV(pad));
 
     /* ... then update state variables */
 
-    PL_comppad_name    = (AV*)(*av_fetch(padlist, 0, FALSE));
-    PL_comppad         = (AV*)(*av_fetch(padlist, 1, FALSE));
+    PL_comppad_name    = MUTABLE_AV((*av_fetch(padlist, 0, FALSE)));
+    PL_comppad         = MUTABLE_AV((*av_fetch(padlist, 1, FALSE)));
     PL_curpad          = AvARRAY(PL_comppad);
 
     if (! (flags & padnew_CLONE)) {
@@ -228,17 +254,21 @@ taken)
 void
 Perl_pad_undef(pTHX_ CV* cv)
 {
+    dVAR;
     I32 ix;
     const PADLIST * const padlist = CvPADLIST(cv);
 
+    PERL_ARGS_ASSERT_PAD_UNDEF;
+
+    pad_peg("pad_undef");
     if (!padlist)
        return;
-    if (!SvREFCNT(CvPADLIST(cv))) /* may be during global destruction */
+    if (SvIS_FREED(padlist)) /* may be during global destruction */
        return;
 
     DEBUG_X(PerlIO_printf(Perl_debug_log,
-         "Pad undef: cv=0x%"UVxf" padlist=0x%"UVxf"\n",
-           PTR2UV(cv), PTR2UV(padlist))
+         "Pad undef: cv=0x%"UVxf" padlist=0x%"UVxf" comppad=0x%"UVxf"\n",
+           PTR2UV(cv), PTR2UV(padlist), PTR2UV(PL_comppad))
     );
 
     /* detach any '&' anon children in the pad; if afterwards they
@@ -247,46 +277,44 @@ Perl_pad_undef(pTHX_ CV* cv)
     /* XXX DAPM for efficiency, we should only do this if we know we have
      * children, or integrate this loop with general cleanup */
 
-    if (!PL_dirty) { /* don't bother during global destruction */
+    if (PL_phase != PERL_PHASE_DESTRUCT) { /* don't bother during global destruction */
        CV * const outercv = CvOUTSIDE(cv);
         const U32 seq = CvOUTSIDE_SEQ(cv);
-       AV *  const comppad_name = (AV*)AvARRAY(padlist)[0];
+       AV *  const comppad_name = MUTABLE_AV(AvARRAY(padlist)[0]);
        SV ** const namepad = AvARRAY(comppad_name);
-       AV *  const comppad = (AV*)AvARRAY(padlist)[1];
+       AV *  const comppad = MUTABLE_AV(AvARRAY(padlist)[1]);
        SV ** const curpad = AvARRAY(comppad);
        for (ix = AvFILLp(comppad_name); ix > 0; ix--) {
            SV * const namesv = namepad[ix];
            if (namesv && namesv != &PL_sv_undef
                && *SvPVX_const(namesv) == '&')
            {
-               CV * const innercv = (CV*)curpad[ix];
+               CV * const innercv = MUTABLE_CV(curpad[ix]);
                U32 inner_rc = SvREFCNT(innercv);
                assert(inner_rc);
-               namepad[ix] = Nullsv;
+               namepad[ix] = NULL;
                SvREFCNT_dec(namesv);
 
                if (SvREFCNT(comppad) < 2) { /* allow for /(?{ sub{} })/  */
-                   curpad[ix] = Nullsv;
+                   curpad[ix] = NULL;
                    SvREFCNT_dec(innercv);
                    inner_rc--;
                }
-               if (inner_rc /* in use, not just a prototype */
-                   && CvOUTSIDE(innercv) == cv)
-               {
+
+               /* in use, not just a prototype */
+               if (inner_rc && (CvOUTSIDE(innercv) == cv)) {
                    assert(CvWEAKOUTSIDE(innercv));
                    /* don't relink to grandfather if he's being freed */
                    if (outercv && SvREFCNT(outercv)) {
                        CvWEAKOUTSIDE_off(innercv);
                        CvOUTSIDE(innercv) = outercv;
                        CvOUTSIDE_SEQ(innercv) = seq;
-                       (void)SvREFCNT_inc(outercv);
+                       SvREFCNT_inc_simple_void_NN(outercv);
                    }
                    else {
-                       CvOUTSIDE(innercv) = Nullcv;
+                       CvOUTSIDE(innercv) = NULL;
                    }
-
                }
-
            }
        }
     }
@@ -294,23 +322,52 @@ Perl_pad_undef(pTHX_ CV* cv)
     ix = AvFILLp(padlist);
     while (ix >= 0) {
        SV* const sv = AvARRAY(padlist)[ix--];
-       if (!sv)
-           continue;
-       if (sv == (SV*)PL_comppad_name)
-           PL_comppad_name = Nullav;
-       else if (sv == (SV*)PL_comppad) {
-           PL_comppad = Null(PAD*);
-           PL_curpad = Null(SV**);
+       if (sv) {
+           if (sv == (const SV *)PL_comppad_name)
+               PL_comppad_name = NULL;
+           else if (sv == (const SV *)PL_comppad) {
+               PL_comppad = NULL;
+               PL_curpad = NULL;
+           }
        }
        SvREFCNT_dec(sv);
     }
-    SvREFCNT_dec((SV*)CvPADLIST(cv));
-    CvPADLIST(cv) = Null(PADLIST*);
+    SvREFCNT_dec(MUTABLE_SV(CvPADLIST(cv)));
+    CvPADLIST(cv) = NULL;
 }
 
 
 
 
+static PADOFFSET
+S_pad_add_name_sv(pTHX_ SV *namesv, const U32 flags, HV *typestash,
+                 HV *ourstash)
+{
+    dVAR;
+    const PADOFFSET offset = pad_alloc(OP_PADSV, SVs_PADMY);
+
+    PERL_ARGS_ASSERT_PAD_ADD_NAME_SV;
+
+    ASSERT_CURPAD_ACTIVE("pad_add_name");
+
+    if (typestash) {
+       assert(SvTYPE(namesv) == SVt_PVMG);
+       SvPAD_TYPED_on(namesv);
+       SvSTASH_set(namesv, MUTABLE_HV(SvREFCNT_inc_simple_NN(MUTABLE_SV(typestash))));
+    }
+    if (ourstash) {
+       SvPAD_OUR_on(namesv);
+       SvOURSTASH_set(namesv, ourstash);
+       SvREFCNT_inc_simple_void_NN(ourstash);
+    }
+    else if (flags & padadd_STATE) {
+       SvPAD_STATE_on(namesv);
+    }
+
+    av_store(PL_comppad_name, offset, namesv);
+    return offset;
+}
+
 /*
 =for apidoc pad_add_name
 
@@ -319,7 +376,7 @@ offset.
 If C<typestash> is valid, the name is for a typed lexical; set the
 name's stash to that value.
 If C<ourstash> is valid, it's an our lexical, set the name's
-GvSTASH to that value
+SvOURSTASH to that value
 
 If fake, it means we're cloning an existing entry
 
@@ -327,53 +384,53 @@ If fake, it means we're cloning an existing entry
 */
 
 PADOFFSET
-Perl_pad_add_name(pTHX_ const char *name, HV* typestash, HV* ourstash, bool fake)
+Perl_pad_add_name(pTHX_ const char *name, const STRLEN len, const U32 flags,
+                 HV *typestash, HV *ourstash)
 {
-    const PADOFFSET offset = pad_alloc(OP_PADSV, SVs_PADMY);
-    SV* const namesv = NEWSV(1102, 0);
+    dVAR;
+    PADOFFSET offset;
+    SV *namesv;
 
-    ASSERT_CURPAD_ACTIVE("pad_add_name");
+    PERL_ARGS_ASSERT_PAD_ADD_NAME;
+
+    if (flags & ~(padadd_OUR|padadd_STATE|padadd_NO_DUP_CHECK))
+       Perl_croak(aTHX_ "panic: pad_add_name illegal flag bits 0x%" UVxf,
+                  (UV)flags);
 
+    namesv = newSV_type((ourstash || typestash) ? SVt_PVMG : SVt_PVNV);
+
+    /* Until we're using the length for real, cross check that we're being told
+       the truth.  */
+    PERL_UNUSED_ARG(len);
+    assert(strlen(name) == len);
 
-    sv_upgrade(namesv, ourstash ? SVt_PVGV : typestash ? SVt_PVMG : SVt_PVNV);
     sv_setpv(namesv, name);
 
-    if (typestash) {
-       SvFLAGS(namesv) |= SVpad_TYPED;
-       SvSTASH_set(namesv, (HV*)SvREFCNT_inc((SV*) typestash));
-    }
-    if (ourstash) {
-       SvFLAGS(namesv) |= SVpad_OUR;
-       GvSTASH(namesv) = ourstash;
-       Perl_sv_add_backref(aTHX_ (SV*)ourstash, namesv);
+    if ((flags & padadd_NO_DUP_CHECK) == 0) {
+       /* check for duplicate declaration */
+       pad_check_dup(namesv, flags & padadd_OUR, ourstash);
     }
 
-    av_store(PL_comppad_name, offset, namesv);
-    if (fake) {
-       SvFAKE_on(namesv);
-       DEBUG_Xv(PerlIO_printf(Perl_debug_log,
-           "Pad addname: %ld \"%s\" FAKE\n", (long)offset, name));
-    }
-    else {
-       /* not yet introduced */
-       SvNV_set(namesv, (NV)PAD_MAX);  /* min */
-       SvIV_set(namesv, 0);            /* max */
-
-       if (!PL_min_intro_pending)
-           PL_min_intro_pending = offset;
-       PL_max_intro_pending = offset;
-       /* if it's not a simple scalar, replace with an AV or HV */
-       /* XXX DAPM since slot has been allocated, replace
-        * av_store with PL_curpad[offset] ? */
-       if (*name == '@')
-           av_store(PL_comppad, offset, (SV*)newAV());
-       else if (*name == '%')
-           av_store(PL_comppad, offset, (SV*)newHV());
-       SvPADMY_on(PL_curpad[offset]);
-       DEBUG_Xv(PerlIO_printf(Perl_debug_log,
-           "Pad addname: %ld \"%s\" new lex=0x%"UVxf"\n",
-           (long)offset, name, PTR2UV(PL_curpad[offset])));
-    }
+    offset = pad_add_name_sv(namesv, flags, typestash, ourstash);
+
+    /* not yet introduced */
+    COP_SEQ_RANGE_LOW_set(namesv, PAD_MAX);    /* min */
+    COP_SEQ_RANGE_HIGH_set(namesv, 0);         /* max */
+
+    if (!PL_min_intro_pending)
+       PL_min_intro_pending = offset;
+    PL_max_intro_pending = offset;
+    /* if it's not a simple scalar, replace with an AV or HV */
+    assert(SvTYPE(PL_curpad[offset]) == SVt_NULL);
+    assert(SvREFCNT(PL_curpad[offset]) == 1);
+    if (*name == '@')
+       sv_upgrade(PL_curpad[offset], SVt_PVAV);
+    else if (*name == '%')
+       sv_upgrade(PL_curpad[offset], SVt_PVHV);
+    assert(SvPADMY(PL_curpad[offset]));
+    DEBUG_Xv(PerlIO_printf(Perl_debug_log,
+                          "Pad addname: %ld \"%s\" new lex=0x%"UVxf"\n",
+                          (long)offset, name, PTR2UV(PL_curpad[offset])));
 
     return offset;
 }
@@ -393,14 +450,20 @@ for a slot which has no name and no active value.
 
 /* XXX DAPM integrate alloc(), add_name() and add_anon(),
  * or at least rationalise ??? */
-
+/* And flag whether the incoming name is UTF8 or 8 bit?
+   Could do this either with the +ve/-ve hack of the HV code, or expanding
+   the flag bits. Either way, this makes proper Unicode safe pad support.
+   NWC
+*/
 
 PADOFFSET
 Perl_pad_alloc(pTHX_ I32 optype, U32 tmptype)
 {
+    dVAR;
     SV *sv;
     I32 retval;
 
+    PERL_UNUSED_ARG(optype);
     ASSERT_CURPAD_ACTIVE("pad_alloc");
 
     if (AvARRAY(PL_comppad) != PL_curpad)
@@ -456,12 +519,17 @@ Add an anon code entry to the current compiling pad
 PADOFFSET
 Perl_pad_add_anon(pTHX_ SV* sv, OPCODE op_type)
 {
+    dVAR;
     PADOFFSET ix;
-    SV* const name = NEWSV(1106, 0);
-    sv_upgrade(name, SVt_PVNV);
-    sv_setpvn(name, "&", 1);
-    SvIV_set(name, -1);
-    SvNV_set(name, 1);
+    SV* const name = newSV_type(SVt_PVNV);
+
+    PERL_ARGS_ASSERT_PAD_ADD_ANON;
+
+    pad_peg("add_anon");
+    sv_setpvs(name, "&");
+    /* Are these two actually ever read? */
+    COP_SEQ_RANGE_HIGH_set(name, ~0);
+    COP_SEQ_RANGE_LOW_set(name, 1);
     ix = pad_alloc(op_type, SVs_PADMY);
     av_store(PL_comppad_name, ix, name);
     /* XXX DAPM use PL_curpad[] ? */
@@ -470,10 +538,10 @@ Perl_pad_add_anon(pTHX_ SV* sv, OPCODE op_type)
 
     /* 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));
+    if (CvOUTSIDE((const CV *)sv)) {
+       assert(!CvWEAKOUTSIDE((const CV *)sv));
+       CvWEAKOUTSIDE_on(MUTABLE_CV(sv));
+       SvREFCNT_dec(CvOUTSIDE(MUTABLE_CV(sv)));
     }
     return ix;
 }
@@ -492,15 +560,20 @@ C<is_our> indicates that the name to check is an 'our' declaration
 =cut
 */
 
-/* XXX DAPM integrate this into pad_add_name ??? */
-
-void
-Perl_pad_check_dup(pTHX_ const char *name, bool is_our, const HV *ourstash)
+STATIC void
+S_pad_check_dup(pTHX_ SV *name, const U32 flags, const HV *ourstash)
 {
+    dVAR;
     SV         **svp;
     PADOFFSET  top, off;
+    const U32  is_our = flags & padadd_OUR;
+
+    PERL_ARGS_ASSERT_PAD_CHECK_DUP;
 
     ASSERT_CURPAD_ACTIVE("pad_check_dup");
+
+    assert((flags & ~padadd_OUR) == 0);
+
     if (AvFILLp(PL_comppad_name) < 0 || !ckWARN(WARN_MISC))
        return; /* nothing to check */
 
@@ -514,16 +587,16 @@ Perl_pad_check_dup(pTHX_ const char *name, bool is_our, const HV *ourstash)
        if (sv
            && sv != &PL_sv_undef
            && !SvFAKE(sv)
-           && (SvIVX(sv) == PAD_MAX || SvIVX(sv) == 0)
-           && strEQ(name, SvPVX_const(sv)))
+           && (COP_SEQ_RANGE_HIGH(sv) == PAD_MAX || COP_SEQ_RANGE_HIGH(sv) == 0)
+           && sv_eq(name, sv))
        {
-           if (is_our && (SvFLAGS(sv) & SVpad_OUR))
+           if (is_our && (SvPAD_OUR(sv)))
                break; /* "our" masking "our" */
            Perl_warner(aTHX_ packWARN(WARN_MISC),
-               "\"%s\" variable %s masks earlier declaration in same %s",
-               (is_our ? "our" : "my"),
-               name,
-               (SvIVX(sv) == PAD_MAX ? "scope" : "statement"));
+               "\"%s\" variable %"SVf" masks earlier declaration in same %s",
+               (is_our ? "our" : PL_parser->in_my == KEY_my ? "my" : "state"),
+               sv,
+               (COP_SEQ_RANGE_HIGH(sv) == PAD_MAX ? "scope" : "statement"));
            --off;
            break;
        }
@@ -535,12 +608,12 @@ Perl_pad_check_dup(pTHX_ const char *name, bool is_our, const HV *ourstash)
            if (sv
                && sv != &PL_sv_undef
                && !SvFAKE(sv)
-               && (SvIVX(sv) == PAD_MAX || SvIVX(sv) == 0)
-               && ((SvFLAGS(sv) & SVpad_OUR) && GvSTASH(sv) == ourstash)
-               && strEQ(name, SvPVX_const(sv)))
+               && (COP_SEQ_RANGE_HIGH(sv) == PAD_MAX || COP_SEQ_RANGE_HIGH(sv) == 0)
+               && SvOURSTASH(sv) == ourstash
+               && sv_eq(name, sv))
            {
                Perl_warner(aTHX_ packWARN(WARN_MISC),
-                   "\"our\" variable %s redeclared", name);
+                   "\"our\" variable %"SVf" redeclared", sv);
                if ((I32)off <= PL_comppad_name_floor)
                    Perl_warner(aTHX_ packWARN(WARN_MISC),
                        "\t(Did you mean \"local\" instead of \"our\"?)\n");
@@ -564,32 +637,52 @@ Returns the offset in the current pad, or NOT_IN_PAD on failure.
 */
 
 PADOFFSET
-Perl_pad_findmy(pTHX_ const char *name)
+Perl_pad_findmy(pTHX_ const char *name, STRLEN len, U32 flags)
 {
+    dVAR;
     SV *out_sv;
     int out_flags;
     I32 offset;
     const AV *nameav;
     SV **name_svp;
 
-    offset =  pad_findlex(name, PL_compcv, PL_cop_seqmax, 1,
-               Null(SV**), &out_sv, &out_flags);
-    if (offset != NOT_IN_PAD) 
+    PERL_ARGS_ASSERT_PAD_FINDMY;
+
+    pad_peg("pad_findmy");
+
+    if (flags)
+       Perl_croak(aTHX_ "panic: pad_findmy illegal flag bits 0x%" UVxf,
+                  (UV)flags);
+
+    /* Yes, it is a bug (read work in progress) that we're not really using this
+       length parameter, and instead relying on strlen() later on. But I'm not
+       comfortable about changing the pad API piecemeal to use and rely on
+       lengths. This only exists to avoid an "unused parameter" warning.  */
+    if (len < 2) 
+       return NOT_IN_PAD;
+
+    /* But until we're using the length for real, cross check that we're being
+       told the truth.  */
+    assert(strlen(name) == len);
+
+    offset = pad_findlex(name, PL_compcv, PL_cop_seqmax, 1,
+               NULL, &out_sv, &out_flags);
+    if ((PADOFFSET)offset != NOT_IN_PAD) 
        return offset;
 
     /* look for an our that's being introduced; this allows
      *    our $foo = 0 unless defined $foo;
      * to not give a warning. (Yes, this is a hack) */
 
-    nameav = (AV*)AvARRAY(CvPADLIST(PL_compcv))[0];
+    nameav = MUTABLE_AV(AvARRAY(CvPADLIST(PL_compcv))[0]);
     name_svp = AvARRAY(nameav);
     for (offset = AvFILLp(nameav); offset > 0; offset--) {
         const SV * const namesv = name_svp[offset];
        if (namesv && namesv != &PL_sv_undef
            && !SvFAKE(namesv)
-           && (SvFLAGS(namesv) & SVpad_OUR)
+           && (SvPAD_OUR(namesv))
            && strEQ(SvPVX_const(namesv), name)
-           && U_32(SvNVX(namesv)) == PAD_MAX /* min */
+           && COP_SEQ_RANGE_LOW(namesv) == PAD_MAX /* min */
        )
            return offset;
     }
@@ -604,10 +697,33 @@ Perl_pad_findmy(pTHX_ const char *name)
 PADOFFSET
 Perl_find_rundefsvoffset(pTHX)
 {
+    dVAR;
     SV *out_sv;
     int out_flags;
     return pad_findlex("$_", find_runcv(NULL), PL_curcop->cop_seq, 1,
-           Null(SV**), &out_sv, &out_flags);
+           NULL, &out_sv, &out_flags);
+}
+
+/*
+ * Returns a lexical $_, if there is one, at run time ; or the global one
+ * otherwise.
+ */
+
+SV *
+Perl_find_rundefsv(pTHX)
+{
+    SV *namesv;
+    int flags;
+    PADOFFSET po;
+
+    po = pad_findlex("$_", find_runcv(NULL), PL_curcop->cop_seq, 1,
+           NULL, &namesv, &flags);
+
+    if (po == NOT_IN_PAD
+       || (SvFLAGS(namesv) & (SVpad_NAME|SVpad_OUR)) == (SVpad_NAME|SVpad_OUR))
+       return DEFSV;
+
+    return PAD_SVl(po);
 }
 
 /*
@@ -627,17 +743,12 @@ associated with the IVX field of a fake namesv.
 
 Note that pad_findlex() is recursive; it recurses up the chain of CVs,
 then comes back down, adding fake entries as it goes. It has to be this way
-because fake namesvs in anon protoypes have to store in NVX the index into
+because fake namesvs in anon protoypes have to store in xlow the index into
 the parent pad.
 
 =cut
 */
 
-/* Flags set in the SvIVX field of FAKE namesvs */
-
-#define PAD_FAKELEX_ANON   1 /* the lex is declared in an ANON, or ... */
-#define PAD_FAKELEX_MULTI  2 /* the lex can be instantiated multiple times */
-
 /* the CV has finished being compiled. This is not a sufficient test for
  * all CVs (eg XSUBs), but suffices for the CVs found in a lexical chain */
 #define CvCOMPILED(cv) CvROOT(cv)
@@ -650,11 +761,14 @@ STATIC PADOFFSET
 S_pad_findlex(pTHX_ const char *name, const CV* cv, U32 seq, int warn,
        SV** out_capture, SV** out_name_sv, int *out_flags)
 {
+    dVAR;
     I32 offset, new_offset;
     SV *new_capture;
     SV **new_capturep;
     const AV * const padlist = CvPADLIST(cv);
 
+    PERL_ARGS_ASSERT_PAD_FINDLEX;
+
     *out_flags = 0;
 
     DEBUG_Xv(PerlIO_printf(Perl_debug_log,
@@ -665,7 +779,7 @@ S_pad_findlex(pTHX_ const char *name, const CV* cv, U32 seq, int warn,
 
     if (padlist) { /* not an undef CV */
        I32 fake_offset = 0;
-        const AV * const nameav = (AV*)AvARRAY(padlist)[0];
+        const AV * const nameav = MUTABLE_AV(AvARRAY(padlist)[0]);
        SV * const * const name_svp = AvARRAY(nameav);
 
        for (offset = AvFILLp(nameav); offset > 0; offset--) {
@@ -675,8 +789,8 @@ S_pad_findlex(pTHX_ const char *name, const CV* cv, U32 seq, int warn,
            {
                if (SvFAKE(namesv))
                    fake_offset = offset; /* in case we don't find a real one */
-               else if (  seq >  U_32(SvNVX(namesv))   /* min */
-                       && seq <= (U32)SvIVX(namesv))   /* max */
+               else if (  seq >  COP_SEQ_RANGE_LOW(namesv)     /* min */
+                       && seq <= COP_SEQ_RANGE_HIGH(namesv))   /* max */
                    break;
            }
        }
@@ -699,18 +813,19 @@ S_pad_findlex(pTHX_ const char *name, const CV* cv, U32 seq, int warn,
                                ? PAD_FAKELEX_MULTI : 0;
 
                DEBUG_Xv(PerlIO_printf(Perl_debug_log,
-                   "Pad findlex cv=0x%"UVxf" matched: offset=%ld (%ld,%ld)\n",
-                   PTR2UV(cv), (long)offset, (long)U_32(SvNVX(*out_name_sv)),
-                   (long)SvIVX(*out_name_sv)));
+                   "Pad findlex cv=0x%"UVxf" matched: offset=%ld (%lu,%lu)\n",
+                   PTR2UV(cv), (long)offset,
+                   (unsigned long)COP_SEQ_RANGE_LOW(*out_name_sv),
+                   (unsigned long)COP_SEQ_RANGE_HIGH(*out_name_sv)));
            }
            else { /* fake match */
                offset = fake_offset;
                *out_name_sv = name_svp[offset]; /* return the namesv */
-               *out_flags = SvIVX(*out_name_sv);
+               *out_flags = PARENT_FAKELEX_FLAGS(*out_name_sv);
                DEBUG_Xv(PerlIO_printf(Perl_debug_log,
                    "Pad findlex cv=0x%"UVxf" matched: offset=%ld flags=0x%lx index=%lu\n",
                    PTR2UV(cv), (long)offset, (unsigned long)*out_flags,
-                       (unsigned long)SvNVX(*out_name_sv) 
+                   (unsigned long) PARENT_PAD_INDEX(*out_name_sv) 
                ));
            }
 
@@ -719,8 +834,8 @@ S_pad_findlex(pTHX_ const char *name, const CV* cv, U32 seq, int warn,
            if (out_capture) {
 
                /* our ? */
-               if ((SvFLAGS(*out_name_sv) & SVpad_OUR)) {
-                   *out_capture = Nullsv;
+               if (SvPAD_OUR(*out_name_sv)) {
+                   *out_capture = NULL;
                    return offset;
                }
 
@@ -729,16 +844,17 @@ S_pad_findlex(pTHX_ const char *name, const CV* cv, U32 seq, int warn,
                        ? CvANON(cv) && CvCLONE(cv) && !CvCLONED(cv)
                        : *out_flags & PAD_FAKELEX_ANON)
                {
-                   if (warn && ckWARN(WARN_CLOSURE))
-                       Perl_warner(aTHX_ packWARN(WARN_CLOSURE),
-                           "Variable \"%s\" is not available", name);
-                   *out_capture = Nullsv;
+                   if (warn)
+                       Perl_ck_warner(aTHX_ packWARN(WARN_CLOSURE),
+                                      "Variable \"%s\" is not available", name);
+                   *out_capture = NULL;
                }
 
                /* real value */
                else {
                    int newwarn = warn;
                    if (!CvCOMPILED(cv) && (*out_flags & PAD_FAKELEX_MULTI)
+                        && !SvPAD_STATE(name_svp[offset])
                         && warn && ckWARN(WARN_CLOSURE)) {
                        newwarn = 0;
                        Perl_warner(aTHX_ packWARN(WARN_CLOSURE),
@@ -761,24 +877,25 @@ S_pad_findlex(pTHX_ const char *name, const CV* cv, U32 seq, int warn,
                        return offset;
                    }
 
-                   *out_capture = AvARRAY((AV*)AvARRAY(padlist)[
-                                   CvDEPTH(cv) ? CvDEPTH(cv) : 1])[offset];
+                   *out_capture = AvARRAY(MUTABLE_AV(AvARRAY(padlist)[
+                                   CvDEPTH(cv) ? CvDEPTH(cv) : 1]))[offset];
                    DEBUG_Xv(PerlIO_printf(Perl_debug_log,
                        "Pad findlex cv=0x%"UVxf" found lex=0x%"UVxf"\n",
                        PTR2UV(cv), PTR2UV(*out_capture)));
 
-                   if (SvPADSTALE(*out_capture)) {
-                       if (ckWARN(WARN_CLOSURE))
-                           Perl_warner(aTHX_ packWARN(WARN_CLOSURE),
-                               "Variable \"%s\" is not available", name);
-                       *out_capture = Nullsv;
+                   if (SvPADSTALE(*out_capture)
+                       && !SvPAD_STATE(name_svp[offset]))
+                   {
+                       Perl_ck_warner(aTHX_ packWARN(WARN_CLOSURE),
+                                      "Variable \"%s\" is not available", name);
+                       *out_capture = NULL;
                    }
                }
                if (!*out_capture) {
                    if (*name == '@')
-                       *out_capture = sv_2mortal((SV*)newAV());
+                       *out_capture = sv_2mortal(MUTABLE_SV(newAV()));
                    else if (*name == '%')
-                       *out_capture = sv_2mortal((SV*)newHV());
+                       *out_capture = sv_2mortal(MUTABLE_SV(newHV()));
                    else
                        *out_capture = sv_newmortal();
                }
@@ -792,17 +909,17 @@ S_pad_findlex(pTHX_ const char *name, const CV* cv, U32 seq, int warn,
 
     if (!CvOUTSIDE(cv))
        return NOT_IN_PAD;
-    
+
     /* out_capture non-null means caller wants us to capture lex; in
      * addition we capture ourselves unless it's an ANON/format */
     new_capturep = out_capture ? out_capture :
-               CvLATE(cv) ? Null(SV**) : &new_capture;
+               CvLATE(cv) ? NULL : &new_capture;
 
     offset = pad_findlex(name, CvOUTSIDE(cv), CvOUTSIDE_SEQ(cv), 1,
                new_capturep, out_name_sv, out_flags);
-    if (offset == NOT_IN_PAD)
+    if ((PADOFFSET)offset == NOT_IN_PAD)
        return NOT_IN_PAD;
-    
+
     /* found in an outer CV. Add appropriate fake entry to this pad */
 
     /* don't add new fake entries (via eval) to CVs that we have already
@@ -811,32 +928,39 @@ S_pad_findlex(pTHX_ const char *name, const CV* cv, U32 seq, int warn,
        return 0; /* this dummy (and invalid) value isnt used by the caller */
 
     {
-       SV *new_namesv;
+       /* This relies on sv_setsv_flags() upgrading the destination to the same
+          type as the source, independant of the flags set, and on it being
+          "good" and only copying flag bits and pointers that it understands.
+       */
+       SV *new_namesv = newSVsv(*out_name_sv);
        AV *  const ocomppad_name = PL_comppad_name;
        PAD * const ocomppad = PL_comppad;
-       PL_comppad_name = (AV*)AvARRAY(padlist)[0];
-       PL_comppad = (AV*)AvARRAY(padlist)[1];
+       PL_comppad_name = MUTABLE_AV(AvARRAY(padlist)[0]);
+       PL_comppad = MUTABLE_AV(AvARRAY(padlist)[1]);
        PL_curpad = AvARRAY(PL_comppad);
 
-       new_offset = pad_add_name(
-           SvPVX_const(*out_name_sv),
-           (SvFLAGS(*out_name_sv) & SVpad_TYPED)
-                   ? SvSTASH(*out_name_sv) : Nullhv,
-           (SvFLAGS(*out_name_sv) & SVpad_OUR)
-                   ? GvSTASH(*out_name_sv) : Nullhv,
-           1  /* fake */
-       );
-
-       new_namesv = AvARRAY(PL_comppad_name)[new_offset];
-       SvIV_set(new_namesv, *out_flags);
-
-       SvNV_set(new_namesv, (NV)0);
-       if (SvFLAGS(new_namesv) & SVpad_OUR) {
-          /* do nothing */
+       new_offset
+           = pad_add_name_sv(new_namesv,
+                             (SvPAD_STATE(*out_name_sv) ? padadd_STATE : 0),
+                             SvPAD_TYPED(*out_name_sv)
+                             ? SvSTASH(*out_name_sv) : NULL,
+                             SvOURSTASH(*out_name_sv)
+                             );
+
+       SvFAKE_on(new_namesv);
+       DEBUG_Xv(PerlIO_printf(Perl_debug_log,
+                              "Pad addname: %ld \"%.*s\" FAKE\n",
+                              (long)new_offset,
+                              (int) SvCUR(new_namesv), SvPVX(new_namesv)));
+       PARENT_FAKELEX_FLAGS_set(new_namesv, *out_flags);
+
+       PARENT_PAD_INDEX_set(new_namesv, 0);
+       if (SvPAD_OUR(new_namesv)) {
+           NOOP;   /* do nothing */
        }
        else if (CvLATE(cv)) {
            /* delayed creation - just note the offset within parent pad */
-           SvNV_set(new_namesv, (NV)offset);
+           PARENT_PAD_INDEX_set(new_namesv, offset);
            CvCLONE_on(cv);
        }
        else {
@@ -847,16 +971,17 @@ S_pad_findlex(pTHX_ const char *name, const CV* cv, U32 seq, int warn,
                PTR2UV(cv), PTR2UV(*new_capturep), (long)new_offset));
        }
        *out_name_sv = new_namesv;
-       *out_flags = SvIVX(new_namesv);
+       *out_flags = PARENT_FAKELEX_FLAGS(new_namesv);
 
        PL_comppad_name = ocomppad_name;
        PL_comppad = ocomppad;
-       PL_curpad = ocomppad ? AvARRAY(ocomppad) : Null(SV **);
+       PL_curpad = ocomppad ? AvARRAY(ocomppad) : NULL;
     }
     return new_offset;
 }
 
-               
+
+#ifdef DEBUGGING
 /*
 =for apidoc pad_sv
 
@@ -870,6 +995,7 @@ Use macro PAD_SV instead of calling this function directly.
 SV *
 Perl_pad_sv(pTHX_ PADOFFSET po)
 {
+    dVAR;
     ASSERT_CURPAD_ACTIVE("pad_sv");
 
     if (!po)
@@ -891,10 +1017,13 @@ Use the macro PAD_SETSV() rather than calling this function directly.
 =cut
 */
 
-#ifdef DEBUGGING
 void
 Perl_pad_setsv(pTHX_ PADOFFSET po, SV* sv)
 {
+    dVAR;
+
+    PERL_ARGS_ASSERT_PAD_SETSV;
+
     ASSERT_CURPAD_ACTIVE("pad_setsv");
 
     DEBUG_X(PerlIO_printf(Perl_debug_log,
@@ -924,6 +1053,7 @@ Update the pad compilation state variables on entry to a new block
 void
 Perl_pad_block_start(pTHX_ int full)
 {
+    dVAR;
     ASSERT_CURPAD_ACTIVE("pad_block_start");
     SAVEI32(PL_comppad_name_floor);
     PL_comppad_name_floor = AvFILLp(PL_comppad_name);
@@ -952,6 +1082,7 @@ Perl_pad_block_start(pTHX_ int full)
 U32
 Perl_intro_my(pTHX)
 {
+    dVAR;
     SV **svp;
     I32 i;
 
@@ -963,13 +1094,14 @@ Perl_intro_my(pTHX)
     for (i = PL_min_intro_pending; i <= PL_max_intro_pending; i++) {
        SV * const sv = svp[i];
 
-       if (sv && sv != &PL_sv_undef && !SvFAKE(sv) && !SvIVX(sv)) {
-           SvIV_set(sv, PAD_MAX);      /* Don't know scope end yet. */
-           SvNV_set(sv, (NV)PL_cop_seqmax);
+       if (sv && sv != &PL_sv_undef && !SvFAKE(sv) && !COP_SEQ_RANGE_HIGH(sv)) {
+           COP_SEQ_RANGE_HIGH_set(sv, PAD_MAX);        /* Don't know scope end yet. */
+           COP_SEQ_RANGE_LOW_set(sv, PL_cop_seqmax);
            DEBUG_Xv(PerlIO_printf(Perl_debug_log,
-               "Pad intromy: %ld \"%s\", (%ld,%ld)\n",
+               "Pad intromy: %ld \"%s\", (%lu,%lu)\n",
                (long)i, SvPVX_const(sv),
-               (long)U_32(SvNVX(sv)), (long)SvIVX(sv))
+               (unsigned long)COP_SEQ_RANGE_LOW(sv),
+               (unsigned long)COP_SEQ_RANGE_HIGH(sv))
            );
        }
     }
@@ -993,6 +1125,7 @@ lexicals in this scope and warn of any lexicals that never got introduced.
 void
 Perl_pad_leavemy(pTHX)
 {
+    dVAR;
     I32 off;
     SV * const * const svp = AvARRAY(PL_comppad_name);
 
@@ -1002,21 +1135,22 @@ Perl_pad_leavemy(pTHX)
     if (PL_min_intro_pending && PL_comppad_name_fill < PL_min_intro_pending) {
        for (off = PL_max_intro_pending; off >= PL_min_intro_pending; off--) {
            const SV * const sv = svp[off];
-           if (sv && sv != &PL_sv_undef
-                   && !SvFAKE(sv) && ckWARN_d(WARN_INTERNAL))
-               Perl_warner(aTHX_ packWARN(WARN_INTERNAL),
-                                       "%"SVf" never introduced", sv);
+           if (sv && sv != &PL_sv_undef && !SvFAKE(sv))
+               Perl_ck_warner_d(aTHX_ packWARN(WARN_INTERNAL),
+                                "%"SVf" never introduced",
+                                SVfARG(sv));
        }
     }
     /* "Deintroduce" my variables that are leaving with this scope. */
     for (off = AvFILLp(PL_comppad_name); off > PL_comppad_name_fill; off--) {
        const SV * const sv = svp[off];
-       if (sv && sv != &PL_sv_undef && !SvFAKE(sv) && SvIVX(sv) == PAD_MAX) {
-           SvIV_set(sv, PL_cop_seqmax);
+       if (sv && sv != &PL_sv_undef && !SvFAKE(sv) && COP_SEQ_RANGE_HIGH(sv) == PAD_MAX) {
+           COP_SEQ_RANGE_HIGH_set(sv, PL_cop_seqmax);
            DEBUG_Xv(PerlIO_printf(Perl_debug_log,
-               "Pad leavemy: %ld \"%s\", (%ld,%ld)\n",
+               "Pad leavemy: %ld \"%s\", (%lu,%lu)\n",
                (long)off, SvPVX_const(sv),
-               (long)U_32(SvNVX(sv)), (long)SvIVX(sv))
+               (unsigned long)COP_SEQ_RANGE_LOW(sv),
+               (unsigned long)COP_SEQ_RANGE_HIGH(sv))
            );
        }
     }
@@ -1038,6 +1172,7 @@ new one.
 void
 Perl_pad_swipe(pTHX_ PADOFFSET po, bool refadjust)
 {
+    dVAR;
     ASSERT_CURPAD_LEGAL("pad_swipe");
     if (!PL_curpad)
        return;
@@ -1059,7 +1194,7 @@ Perl_pad_swipe(pTHX_ PADOFFSET po, bool refadjust)
     /* if pad tmps aren't shared between ops, then there's no need to
      * create a new tmp when an existing op is freed */
 #ifdef USE_BROKEN_PAD_RESET
-    PL_curpad[po] = NEWSV(1107,0);
+    PL_curpad[po] = newSV(0);
     SvPADTMP_on(PL_curpad[po]);
 #else
     PL_curpad[po] = &PL_sv_undef;
@@ -1083,9 +1218,10 @@ Mark all the current temporaries for reuse
  * to  a shared TARG.  Such an alias will change randomly and unpredictably.
  * We avoid doing this until we can think of a Better Way.
  * GSAR 97-10-29 */
-void
-Perl_pad_reset(pTHX)
+static void
+S_pad_reset(pTHX)
 {
+    dVAR;
 #ifdef USE_BROKEN_PAD_RESET
     if (AvARRAY(PL_comppad) != PL_curpad)
        Perl_croak(aTHX_ "panic: pad_reset curpad");
@@ -1157,7 +1293,7 @@ Perl_pad_tidy(pTHX_ padtidy_type type)
 
     /* extend curpad to match namepad */
     if (AvFILLp(PL_comppad_name) < AvFILLp(PL_comppad))
-       av_store(PL_comppad_name, AvFILLp(PL_comppad), Nullsv);
+       av_store(PL_comppad_name, AvFILLp(PL_comppad), NULL);
 
     if (type == padtidy_SUBCLONE) {
        SV * const * const namep = AvARRAY(PL_comppad_name);
@@ -1173,39 +1309,49 @@ Perl_pad_tidy(pTHX_ padtidy_type type)
             * pad are anonymous subs.
             * The rest are created anew during cloning.
             */
-           if (!((namesv = namep[ix]) != Nullsv &&
+           if (!((namesv = namep[ix]) != NULL &&
                  namesv != &PL_sv_undef &&
                   *SvPVX_const(namesv) == '&'))
            {
                SvREFCNT_dec(PL_curpad[ix]);
-               PL_curpad[ix] = Nullsv;
+               PL_curpad[ix] = NULL;
            }
        }
     }
     else if (type == padtidy_SUB) {
        /* XXX DAPM this same bit of code keeps appearing !!! Rationalise? */
        AV * const av = newAV();                        /* Will be @_ */
-       av_extend(av, 0);
-       av_store(PL_comppad, 0, (SV*)av);
+       av_store(PL_comppad, 0, MUTABLE_SV(av));
        AvREIFY_only(av);
     }
 
-    /* XXX DAPM rationalise these two similar branches */
-
-    if (type == padtidy_SUB) {
+    if (type == padtidy_SUB || type == padtidy_FORMAT) {
+       SV * const * const namep = AvARRAY(PL_comppad_name);
        PADOFFSET ix;
        for (ix = AvFILLp(PL_comppad); ix > 0; ix--) {
            if (SvIMMORTAL(PL_curpad[ix]) || IS_PADGV(PL_curpad[ix]) || IS_PADCONST(PL_curpad[ix]))
                continue;
-           if (!SvPADMY(PL_curpad[ix]))
-               SvPADTMP_on(PL_curpad[ix]);
-       }
-    }
-    else if (type == padtidy_FORMAT) {
-       PADOFFSET ix;
-       for (ix = AvFILLp(PL_comppad); ix > 0; ix--) {
-           if (!SvPADMY(PL_curpad[ix]) && !SvIMMORTAL(PL_curpad[ix]))
+           if (!SvPADMY(PL_curpad[ix])) {
                SvPADTMP_on(PL_curpad[ix]);
+           } else if (!SvFAKE(namep[ix])) {
+               /* This is a work around for how the current implementation of
+                  ?{ } blocks in regexps interacts with lexicals.
+
+                  One of our lexicals.
+                  Can't do this on all lexicals, otherwise sub baz() won't
+                  compile in
+
+                  my $foo;
+
+                  sub bar { ++$foo; }
+
+                  sub baz { ++$foo; }
+
+                  because completion of compiling &bar calling pad_tidy()
+                  would cause (top level) $foo to be marked as stale, and
+                  "no longer available".  */
+               SvPADSTALE_on(PL_curpad[ix]);
+           }
        }
     }
     PL_curpad = AvARRAY(PL_comppad);
@@ -1224,6 +1370,7 @@ Free the SV at offset po in the current pad.
 void
 Perl_pad_free(pTHX_ PADOFFSET po)
 {
+    dVAR;
     ASSERT_CURPAD_LEGAL("pad_free");
     if (!PL_curpad)
        return;
@@ -1241,13 +1388,7 @@ Perl_pad_free(pTHX_ PADOFFSET po)
        SvPADTMP_off(PL_curpad[po]);
 #ifdef USE_ITHREADS
        /* SV could be a shared hash key (eg bugid #19022) */
-       if (
-#ifdef PERL_OLD_COPY_ON_WRITE
-           !SvIsCOW(PL_curpad[po])
-#else
-           !SvFAKE(PL_curpad[po])
-#endif
-           )
+       if (!SvIsCOW(PL_curpad[po]))
            SvREADONLY_off(PL_curpad[po]);      /* could be a freed constant */
 #endif
     }
@@ -1268,17 +1409,20 @@ Dump the contents of a padlist
 void
 Perl_do_dump_pad(pTHX_ I32 level, PerlIO *file, PADLIST *padlist, int full)
 {
+    dVAR;
     const AV *pad_name;
     const AV *pad;
     SV **pname;
     SV **ppad;
     I32 ix;
 
+    PERL_ARGS_ASSERT_DO_DUMP_PAD;
+
     if (!padlist) {
        return;
     }
-    pad_name = (AV*)*av_fetch((AV*)padlist, 0, FALSE);
-    pad = (AV*)*av_fetch((AV*)padlist, 1, FALSE);
+    pad_name = MUTABLE_AV(*av_fetch(MUTABLE_AV(padlist), 0, FALSE));
+    pad = MUTABLE_AV(*av_fetch(MUTABLE_AV(padlist), 1, FALSE));
     pname = AvARRAY(pad_name);
     ppad = AvARRAY(pad);
     Perl_dump_indent(aTHX_ level, file,
@@ -1289,7 +1433,7 @@ Perl_do_dump_pad(pTHX_ I32 level, PerlIO *file, PADLIST *padlist, int full)
     for (ix = 1; ix <= AvFILLp(pad_name); ix++) {
         const SV *namesv = pname[ix];
        if (namesv && namesv == &PL_sv_undef) {
-           namesv = Nullsv;
+           namesv = NULL;
        }
        if (namesv) {
            if (SvFAKE(namesv))
@@ -1299,18 +1443,18 @@ Perl_do_dump_pad(pTHX_ I32 level, PerlIO *file, PADLIST *padlist, int full)
                    PTR2UV(ppad[ix]),
                    (unsigned long) (ppad[ix] ? SvREFCNT(ppad[ix]) : 0),
                    SvPVX_const(namesv),
-                   (unsigned long)SvIVX(namesv),
-                   (unsigned long)SvNVX(namesv)
+                   (unsigned long)PARENT_FAKELEX_FLAGS(namesv),
+                   (unsigned long)PARENT_PAD_INDEX(namesv)
 
                );
            else
                Perl_dump_indent(aTHX_ level+1, file,
-                   "%2d. 0x%"UVxf"<%lu> (%ld,%ld) \"%s\"\n",
+                   "%2d. 0x%"UVxf"<%lu> (%lu,%lu) \"%s\"\n",
                    (int) ix,
                    PTR2UV(ppad[ix]),
                    (unsigned long) (ppad[ix] ? SvREFCNT(ppad[ix]) : 0),
-                   (long)U_32(SvNVX(namesv)),
-                   (long)SvIVX(namesv),
+                   (unsigned long)COP_SEQ_RANGE_LOW(namesv),
+                   (unsigned long)COP_SEQ_RANGE_HIGH(namesv),
                    SvPVX_const(namesv)
                );
        }
@@ -1339,9 +1483,12 @@ dump the contents of a CV
 STATIC void
 S_cv_dump(pTHX_ const CV *cv, const char *title)
 {
+    dVAR;
     const CV * const outside = CvOUTSIDE(cv);
     AV* const padlist = CvPADLIST(cv);
 
+    PERL_ARGS_ASSERT_CV_DUMP;
+
     PerlIO_printf(Perl_debug_log,
                  "  %s: CV=0x%"UVxf" (%s), OUTSIDE=0x%"UVxf" (%s)\n",
                  title,
@@ -1384,8 +1531,8 @@ Perl_cv_clone(pTHX_ CV *proto)
     dVAR;
     I32 ix;
     AV* const protopadlist = CvPADLIST(proto);
-    const AV* const protopad_name = (AV*)*av_fetch(protopadlist, 0, FALSE);
-    const AV* const protopad = (AV*)*av_fetch(protopadlist, 1, FALSE);
+    const AV *const protopad_name = (const AV *)*av_fetch(protopadlist, 0, FALSE);
+    const AV *const protopad = (const AV *)*av_fetch(protopadlist, 1, FALSE);
     SV** const pname = AvARRAY(protopad_name);
     SV** const ppad = AvARRAY(protopad);
     const I32 fname = AvFILLp(protopad_name);
@@ -1395,6 +1542,8 @@ Perl_cv_clone(pTHX_ CV *proto)
     CV* outside;
     long depth;
 
+    PERL_ARGS_ASSERT_CV_CLONE;
+
     assert(!CvUNIQUE(proto));
 
     /* Since cloneable anon subs can be nested, CvOUTSIDE may point
@@ -1413,28 +1562,27 @@ Perl_cv_clone(pTHX_ CV *proto)
     ENTER;
     SAVESPTR(PL_compcv);
 
-    cv = PL_compcv = (CV*)NEWSV(1104, 0);
-    sv_upgrade((SV *)cv, SvTYPE(proto));
-    CvFLAGS(cv) = CvFLAGS(proto) & ~(CVf_CLONE|CVf_WEAKOUTSIDE);
+    cv = PL_compcv = MUTABLE_CV(newSV_type(SvTYPE(proto)));
+    CvFLAGS(cv) = CvFLAGS(proto) & ~(CVf_CLONE|CVf_WEAKOUTSIDE|CVf_CVGV_RC);
     CvCLONED_on(cv);
 
 #ifdef USE_ITHREADS
-    CvFILE(cv)         = CvXSUB(proto) ? CvFILE(proto)
-                                       : savepv(CvFILE(proto));
+    CvFILE(cv)         = CvISXSUB(proto) ? CvFILE(proto)
+                                         : savepv(CvFILE(proto));
 #else
     CvFILE(cv)         = CvFILE(proto);
 #endif
-    CvGV(cv)           = CvGV(proto);
-    CvSTASH(cv)                = CvSTASH(proto);
+    CvGV_set(cv,CvGV(proto));
+    CvSTASH_set(cv, CvSTASH(proto));
     OP_REFCNT_LOCK;
     CvROOT(cv)         = OpREFCNT_inc(CvROOT(proto));
     OP_REFCNT_UNLOCK;
     CvSTART(cv)                = CvSTART(proto);
-    CvOUTSIDE(cv)      = (CV*)SvREFCNT_inc(outside);
+    CvOUTSIDE(cv)      = MUTABLE_CV(SvREFCNT_inc_simple(outside));
     CvOUTSIDE_SEQ(cv) = CvOUTSIDE_SEQ(proto);
 
     if (SvPOK(proto))
-       sv_setpvn((SV*)cv, SvPVX_const(proto), SvCUR(proto));
+       sv_setpvn(MUTABLE_SV(cv), SvPVX_const(proto), SvCUR(proto));
 
     CvPADLIST(cv) = pad_new(padnew_CLONE|padnew_SAVE);
 
@@ -1447,42 +1595,44 @@ Perl_cv_clone(pTHX_ CV *proto)
     outpad = AvARRAY(AvARRAY(CvPADLIST(outside))[depth]);
 
     for (ix = fpad; ix > 0; ix--) {
-       SV* const namesv = (ix <= fname) ? pname[ix] : Nullsv;
-       SV *sv = Nullsv;
+       SV* const namesv = (ix <= fname) ? pname[ix] : NULL;
+       SV *sv = NULL;
        if (namesv && namesv != &PL_sv_undef) { /* lexical */
            if (SvFAKE(namesv)) {   /* lexical from outside? */
-               sv = outpad[(I32)SvNVX(namesv)];
+               sv = outpad[PARENT_PAD_INDEX(namesv)];
                assert(sv);
-               /* formats may have an inactive parent */
-               if (SvTYPE(proto) == SVt_PVFM && SvPADSTALE(sv)) {
-                   if (ckWARN(WARN_CLOSURE))
-                       Perl_warner(aTHX_ packWARN(WARN_CLOSURE),
-                           "Variable \"%s\" is not available", SvPVX_const(namesv));
-                   sv = Nullsv;
-               }
-               else {
-                   assert(!SvPADSTALE(sv));
-                   sv = SvREFCNT_inc(sv);
+               /* formats may have an inactive parent,
+                  while my $x if $false can leave an active var marked as
+                  stale. And state vars are always available */
+               if (SvPADSTALE(sv) && !SvPAD_STATE(namesv)) {
+                   Perl_ck_warner(aTHX_ packWARN(WARN_CLOSURE),
+                                  "Variable \"%s\" is not available", SvPVX_const(namesv));
+                   sv = NULL;
                }
+               else 
+                   SvREFCNT_inc_simple_void_NN(sv);
            }
            if (!sv) {
                 const char sigil = SvPVX_const(namesv)[0];
                 if (sigil == '&')
                    sv = SvREFCNT_inc(ppad[ix]);
                 else if (sigil == '@')
-                   sv = (SV*)newAV();
+                   sv = MUTABLE_SV(newAV());
                 else if (sigil == '%')
-                   sv = (SV*)newHV();
+                   sv = MUTABLE_SV(newHV());
                else
-                   sv = NEWSV(0, 0);
+                   sv = newSV(0);
                SvPADMY_on(sv);
+               /* reset the 'assign only once' flag on each state var */
+               if (SvPAD_STATE(namesv))
+                   SvPADSTALE_on(sv);
            }
        }
        else if (IS_PADGV(ppad[ix]) || IS_PADCONST(ppad[ix])) {
-           sv = SvREFCNT_inc(ppad[ix]);
+           sv = SvREFCNT_inc_NN(ppad[ix]);
        }
        else {
-           sv = NEWSV(0, 0);
+           sv = newSV(0);
            SvPADTMP_on(sv);
        }
        PL_curpad[ix] = sv;
@@ -1506,7 +1656,7 @@ Perl_cv_clone(pTHX_ CV *proto)
        SV* const const_sv = op_const_sv(CvSTART(cv), cv);
        if (const_sv) {
            SvREFCNT_dec(cv);
-           cv = newCONSTSUB(CvSTASH(proto), Nullch, const_sv);
+           cv = newCONSTSUB(CvSTASH(proto), NULL, const_sv);
        }
        else {
            CvCONST_off(cv);
@@ -1530,17 +1680,22 @@ moved to a pre-existing CV struct.
 void
 Perl_pad_fixup_inner_anons(pTHX_ PADLIST *padlist, CV *old_cv, CV *new_cv)
 {
+    dVAR;
     I32 ix;
-    AV * const comppad_name = (AV*)AvARRAY(padlist)[0];
-    AV * const comppad = (AV*)AvARRAY(padlist)[1];
+    AV * const comppad_name = MUTABLE_AV(AvARRAY(padlist)[0]);
+    AV * const comppad = MUTABLE_AV(AvARRAY(padlist)[1]);
     SV ** const namepad = AvARRAY(comppad_name);
     SV ** const curpad = AvARRAY(comppad);
+
+    PERL_ARGS_ASSERT_PAD_FIXUP_INNER_ANONS;
+    PERL_UNUSED_ARG(old_cv);
+
     for (ix = AvFILLp(comppad_name); ix > 0; ix--) {
         const SV * const namesv = namepad[ix];
        if (namesv && namesv != &PL_sv_undef
            && *SvPVX_const(namesv) == '&')
        {
-           CV * const innercv = (CV*)curpad[ix];
+           CV * const innercv = MUTABLE_CV(curpad[ix]);
            assert(CvWEAKOUTSIDE(innercv));
            assert(CvOUTSIDE(innercv) == old_cv);
            CvOUTSIDE(innercv) = new_cv;
@@ -1562,53 +1717,56 @@ the new pad an @_ in slot zero.
 void
 Perl_pad_push(pTHX_ PADLIST *padlist, int depth)
 {
-    if (depth <= AvFILLp(padlist))
-       return;
+    dVAR;
 
-    {
+    PERL_ARGS_ASSERT_PAD_PUSH;
+
+    if (depth > AvFILLp(padlist)) {
        SV** const svp = AvARRAY(padlist);
        AV* const newpad = newAV();
        SV** const oldpad = AvARRAY(svp[depth-1]);
-       I32 ix = AvFILLp((AV*)svp[1]);
-        const I32 names_fill = AvFILLp((AV*)svp[0]);
+       I32 ix = AvFILLp((const AV *)svp[1]);
+        const I32 names_fill = AvFILLp((const AV *)svp[0]);
        SV** const names = AvARRAY(svp[0]);
        AV *av;
 
        for ( ;ix > 0; ix--) {
            if (names_fill >= ix && names[ix] != &PL_sv_undef) {
                const char sigil = SvPVX_const(names[ix])[0];
-               if ((SvFLAGS(names[ix]) & SVf_FAKE) || sigil == '&') {
+               if ((SvFLAGS(names[ix]) & SVf_FAKE)
+                       || (SvFLAGS(names[ix]) & SVpad_STATE)
+                       || sigil == '&')
+               {
                    /* outer lexical or anon code */
                    av_store(newpad, ix, SvREFCNT_inc(oldpad[ix]));
                }
                else {          /* our own lexical */
                    SV *sv; 
                    if (sigil == '@')
-                       sv = (SV*)newAV();
+                       sv = MUTABLE_SV(newAV());
                    else if (sigil == '%')
-                       sv = (SV*)newHV();
+                       sv = MUTABLE_SV(newHV());
                    else
-                       sv = NEWSV(0, 0);
+                       sv = newSV(0);
                    av_store(newpad, ix, sv);
                    SvPADMY_on(sv);
                }
            }
            else if (IS_PADGV(oldpad[ix]) || IS_PADCONST(oldpad[ix])) {
-               av_store(newpad, ix, SvREFCNT_inc(oldpad[ix]));
+               av_store(newpad, ix, SvREFCNT_inc_NN(oldpad[ix]));
            }
            else {
                /* save temporaries on recursion? */
-               SV * const sv = NEWSV(0, 0);
+               SV * const sv = newSV(0);
                av_store(newpad, ix, sv);
                SvPADTMP_on(sv);
            }
        }
        av = newAV();
-       av_extend(av, 0);
-       av_store(newpad, 0, (SV*)av);
+       av_store(newpad, 0, MUTABLE_SV(av));
        AvREIFY_only(av);
 
-       av_store(padlist, depth, (SV*)newpad);
+       av_store(padlist, depth, MUTABLE_SV(newpad));
        AvFILLp(padlist) = depth;
     }
 }
@@ -1617,13 +1775,137 @@ Perl_pad_push(pTHX_ PADLIST *padlist, int depth)
 HV *
 Perl_pad_compname_type(pTHX_ const PADOFFSET po)
 {
+    dVAR;
     SV* const * const av = av_fetch(PL_comppad_name, po, FALSE);
-    if ( SvFLAGS(*av) & SVpad_TYPED ) {
+    if ( SvPAD_TYPED(*av) ) {
         return SvSTASH(*av);
     }
-    return Nullhv;
+    return NULL;
 }
 
+#if defined(USE_ITHREADS)
+
+#  define av_dup_inc(s,t)      MUTABLE_AV(sv_dup_inc((const SV *)s,t))
+
+AV *
+Perl_padlist_dup(pTHX_ AV *const srcpad, CLONE_PARAMS *const param)
+{
+    AV *dstpad;
+    PERL_ARGS_ASSERT_PADLIST_DUP;
+
+    if (!srcpad)
+       return NULL;
+
+    assert(!AvREAL(srcpad));
+
+    if (param->flags & CLONEf_COPY_STACKS
+       || SvREFCNT(AvARRAY(srcpad)[1]) > 1) {
+       /* XXX padlists are real, but pretend to be not */
+       AvREAL_on(srcpad);
+       dstpad = av_dup_inc(srcpad, param);
+       AvREAL_off(srcpad);
+       AvREAL_off(dstpad);
+       assert (SvREFCNT(AvARRAY(srcpad)[1]) == 1);
+    } else {
+       /* CvDEPTH() on our subroutine will be set to 0, so there's no need
+          to build anything other than the first level of pads.  */
+
+       I32 ix = AvFILLp((const AV *)AvARRAY(srcpad)[1]);
+       AV *pad1;
+       const I32 names_fill = AvFILLp((const AV *)(AvARRAY(srcpad)[0]));
+       const AV *const srcpad1 = (const AV *) AvARRAY(srcpad)[1];
+       SV **oldpad = AvARRAY(srcpad1);
+       SV **names;
+       SV **pad1a;
+       AV *args;
+       /* look for it in the table first.
+          I *think* that it shouldn't be possible to find it there.
+          Well, except for how Perl_sv_compile_2op() "works" :-(   */
+       dstpad = (AV*)ptr_table_fetch(PL_ptr_table, srcpad);
+
+       if (dstpad)
+           return dstpad;
+
+       dstpad = newAV();
+       ptr_table_store(PL_ptr_table, srcpad, dstpad);
+       AvREAL_off(dstpad);
+       av_extend(dstpad, 1);
+       AvARRAY(dstpad)[0] = MUTABLE_SV(av_dup_inc(AvARRAY(srcpad)[0], param));
+       names = AvARRAY(AvARRAY(dstpad)[0]);
+
+       pad1 = newAV();
+
+       av_extend(pad1, ix);
+       AvARRAY(dstpad)[1] = MUTABLE_SV(pad1);
+       pad1a = AvARRAY(pad1);
+       AvFILLp(dstpad) = 1;
+
+       if (ix > -1) {
+           AvFILLp(pad1) = ix;
+
+           for ( ;ix > 0; ix--) {
+               if (!oldpad[ix]) {
+                   pad1a[ix] = NULL;
+               } else if (names_fill >= ix && names[ix] != &PL_sv_undef) {
+                   const char sigil = SvPVX_const(names[ix])[0];
+                   if ((SvFLAGS(names[ix]) & SVf_FAKE)
+                       || (SvFLAGS(names[ix]) & SVpad_STATE)
+                       || sigil == '&')
+                       {
+                           /* outer lexical or anon code */
+                           pad1a[ix] = sv_dup_inc(oldpad[ix], param);
+                       }
+                   else {              /* our own lexical */
+                       if(SvPADSTALE(oldpad[ix]) && SvREFCNT(oldpad[ix]) > 1) {
+                           /* This is a work around for how the current
+                              implementation of ?{ } blocks in regexps
+                              interacts with lexicals.  */
+                           pad1a[ix] = sv_dup_inc(oldpad[ix], param);
+                       } else {
+                           SV *sv; 
+                           
+                           if (sigil == '@')
+                               sv = MUTABLE_SV(newAV());
+                           else if (sigil == '%')
+                               sv = MUTABLE_SV(newHV());
+                           else
+                               sv = newSV(0);
+                           pad1a[ix] = sv;
+                           SvPADMY_on(sv);
+                       }
+                   }
+               }
+               else if (IS_PADGV(oldpad[ix]) || IS_PADCONST(oldpad[ix])) {
+                   pad1a[ix] = sv_dup_inc(oldpad[ix], param);
+               }
+               else {
+                   /* save temporaries on recursion? */
+                   SV * const sv = newSV(0);
+                   pad1a[ix] = sv;
+
+                   /* SvREFCNT(oldpad[ix]) != 1 for some code in threads.xs
+                      FIXTHAT before merging this branch.
+                      (And I know how to) */
+                   if (SvPADMY(oldpad[ix]))
+                       SvPADMY_on(sv);
+                   else
+                       SvPADTMP_on(sv);
+               }
+           }
+
+           if (oldpad[0]) {
+               args = newAV();                 /* Will be @_ */
+               AvREIFY_only(args);
+               pad1a[0] = (SV *)args;
+           }
+       }
+    }
+
+    return dstpad;
+}
+
+#endif
+
 /*
  * Local variables:
  * c-indentation-style: bsd