X-Git-Url: https://perl5.git.perl.org/perl5.git/blobdiff_plain/b15aece354b2aec9d338e59acb2abc2deeebc3c0..cc26ddeba958e8f9785b940e55b354e757252c7f:/pad.c diff --git a/pad.c b/pad.c index 2cff24d..e8ba139 100644 --- 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 lexicals, the type is SVt_PVGV, and GvSTASH points at the -stash of the associated global (so that duplicate C delarations 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 lexicals, the type is also SVt_PVMG, with the +SvOURSTASH slot pointing at the stash of the associated global (so that +duplicate C 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 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,29 @@ 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; + PERL_ARGS_ASSERT_PAD_PEG; + + pegcnt++; +} +#endif /* =for apidoc pad_new @@ -132,6 +157,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 +178,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 +200,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 +253,21 @@ taken) void Perl_pad_undef(pTHX_ CV* cv) { + dVAR; I32 ix; - const PADLIST *padlist = CvPADLIST(cv); + 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 @@ -248,69 +277,96 @@ Perl_pad_undef(pTHX_ CV* cv) * children, or integrate this loop with general cleanup */ if (!PL_dirty) { /* don't bother during global destruction */ - CV *outercv = CvOUTSIDE(cv); + CV * const outercv = CvOUTSIDE(cv); const U32 seq = CvOUTSIDE_SEQ(cv); - AV *comppad_name = (AV*)AvARRAY(padlist)[0]; - SV **namepad = AvARRAY(comppad_name); - AV *comppad = (AV*)AvARRAY(padlist)[1]; - SV **curpad = AvARRAY(comppad); + AV * const comppad_name = MUTABLE_AV(AvARRAY(padlist)[0]); + SV ** const namepad = AvARRAY(comppad_name); + AV * const comppad = MUTABLE_AV(AvARRAY(padlist)[1]); + SV ** const curpad = AvARRAY(comppad); for (ix = AvFILLp(comppad_name); ix > 0; ix--) { - SV *namesv = namepad[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; } - } - } } } ix = AvFILLp(padlist); while (ix >= 0) { - SV* 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**); + SV* const sv = AvARRAY(padlist)[ix--]; + 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 +375,7 @@ offset. If C is valid, the name is for a typed lexical; set the name's stash to that value. If C 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,52 +383,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) { - PADOFFSET offset = pad_alloc(OP_PADSV, SVs_PADMY); - SV* 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) = (HV*)SvREFCNT_inc((SV*) ourstash); + 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; } @@ -385,21 +442,27 @@ Perl_pad_add_name(pTHX_ const char *name, HV* typestash, HV* ourstash, bool fake Allocate a new my or tmp pad entry. For a my, simply push a null SV onto the end of PL_comppad, but for a tmp, scan the pad from PL_padix upwards -for a slot which has no name and and no active value. +for a slot which has no name and no active value. =cut */ /* 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) @@ -411,7 +474,7 @@ Perl_pad_alloc(pTHX_ I32 optype, U32 tmptype) retval = AvFILLp(PL_comppad); } else { - SV **names = AvARRAY(PL_comppad_name); + SV * const * const names = AvARRAY(PL_comppad_name); const SSize_t names_fill = AvFILLp(PL_comppad_name); for (;;) { /* @@ -455,14 +518,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* name; + SV* const name = newSV_type(SVt_PVNV); - name = NEWSV(1106, 0); - sv_upgrade(name, SVt_PVNV); - sv_setpvn(name, "&", 1); - SvIV_set(name, -1); - SvNV_set(name, 1); + 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[] ? */ @@ -471,10 +537,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; } @@ -493,16 +559,21 @@ C 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) { - SV **svp, *sv; + 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"); - if (!ckWARN(WARN_MISC) || AvFILLp(PL_comppad_name) < 0) + + assert((flags & ~padadd_OUR) == 0); + + if (AvFILLp(PL_comppad_name) < 0 || !ckWARN(WARN_MISC)) return; /* nothing to check */ svp = AvARRAY(PL_comppad_name); @@ -511,19 +582,20 @@ Perl_pad_check_dup(pTHX_ const char *name, bool is_our, const HV *ourstash) /* XXX DAPM - why the (I32) cast - shouldn't we ensure they're the same * type ? */ for (off = top; (I32)off > PL_comppad_name_floor; off--) { - if ((sv = svp[off]) + SV * const sv = svp[off]; + if (sv && sv != &PL_sv_undef && !SvFAKE(sv) - && (SvIVX(sv) == PAD_MAX || SvIVX(sv) == 0) - && (!is_our - || ((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) + && sv_eq(name, sv)) { + 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; } @@ -531,17 +603,19 @@ Perl_pad_check_dup(pTHX_ const char *name, bool is_our, const HV *ourstash) /* check the rest of the pad */ if (is_our) { do { - if ((sv = svp[off]) + SV * const sv = svp[off]; + 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); - Perl_warner(aTHX_ packWARN(WARN_MISC), - "\t(Did you mean \"local\" instead of \"our\"?)\n"); + "\"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"); break; } } while ( off-- > 0 ); @@ -562,32 +636,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 *namesv = name_svp[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; } @@ -602,10 +696,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); } /* @@ -625,17 +742,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) @@ -648,10 +760,13 @@ 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 *padlist = CvPADLIST(cv); + const AV * const padlist = CvPADLIST(cv); + + PERL_ARGS_ASSERT_PAD_FINDLEX; *out_flags = 0; @@ -663,18 +778,18 @@ 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 *nameav = (AV*)AvARRAY(padlist)[0]; - SV **name_svp = AvARRAY(nameav); + const AV * const nameav = MUTABLE_AV(AvARRAY(padlist)[0]); + SV * const * const name_svp = AvARRAY(nameav); for (offset = AvFILLp(nameav); offset > 0; offset--) { - const SV *namesv = name_svp[offset]; + const SV * const namesv = name_svp[offset]; if (namesv && namesv != &PL_sv_undef && strEQ(SvPVX_const(namesv), name)) { 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; } } @@ -697,18 +812,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) )); } @@ -717,8 +833,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; } @@ -727,16 +843,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), @@ -752,30 +869,32 @@ S_pad_findlex(pTHX_ const char *name, const CV* cv, U32 seq, int warn, "Pad findlex cv=0x%"UVxf" chasing lex in outer pad\n", PTR2UV(cv))); n = *out_name_sv; - pad_findlex(name, CvOUTSIDE(cv), CvOUTSIDE_SEQ(cv), + (void) pad_findlex(name, CvOUTSIDE(cv), + CvOUTSIDE_SEQ(cv), newwarn, out_capture, out_name_sv, out_flags); *out_name_sv = n; 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(); } @@ -789,17 +908,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 @@ -808,32 +927,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; - AV *ocomppad_name = PL_comppad_name; - PAD *ocomppad = PL_comppad; - PL_comppad_name = (AV*)AvARRAY(padlist)[0]; - PL_comppad = (AV*)AvARRAY(padlist)[1]; + /* 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 = 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 { @@ -844,16 +970,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 @@ -867,6 +994,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) @@ -888,10 +1016,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, @@ -921,6 +1052,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); @@ -949,8 +1081,8 @@ Perl_pad_block_start(pTHX_ int full) U32 Perl_intro_my(pTHX) { + dVAR; SV **svp; - SV *sv; I32 i; ASSERT_CURPAD_ACTIVE("intro_my"); @@ -959,15 +1091,16 @@ Perl_intro_my(pTHX) svp = AvARRAY(PL_comppad_name); for (i = PL_min_intro_pending; i <= PL_max_intro_pending; i++) { - if ((sv = svp[i]) && 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); + SV * const sv = svp[i]; + + 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)) ); } } @@ -991,32 +1124,32 @@ lexicals in this scope and warn of any lexicals that never got introduced. void Perl_pad_leavemy(pTHX) { + dVAR; I32 off; - SV **svp = AvARRAY(PL_comppad_name); + SV * const * const svp = AvARRAY(PL_comppad_name); PL_pad_reset_pending = FALSE; ASSERT_CURPAD_ACTIVE("pad_leavemy"); 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 *sv; - if ((sv = svp[off]) && sv != &PL_sv_undef - && !SvFAKE(sv) && ckWARN_d(WARN_INTERNAL)) - Perl_warner(aTHX_ packWARN(WARN_INTERNAL), - "%"SVf" never introduced", sv); + const SV * const sv = svp[off]; + 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 *sv; - if ((sv = svp[off]) && sv != &PL_sv_undef - && !SvFAKE(sv) && SvIVX(sv) == PAD_MAX) - { - SvIV_set(sv, PL_cop_seqmax); + const SV * const sv = svp[off]; + 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 +1171,7 @@ new one. void Perl_pad_swipe(pTHX_ PADOFFSET po, bool refadjust) { + dVAR; ASSERT_CURPAD_LEGAL("pad_swipe"); if (!PL_curpad) return; @@ -1055,8 +1189,15 @@ Perl_pad_swipe(pTHX_ PADOFFSET po, bool refadjust) if (refadjust) SvREFCNT_dec(PL_curpad[po]); - PL_curpad[po] = NEWSV(1107,0); + + /* 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(0); SvPADTMP_on(PL_curpad[po]); +#else + PL_curpad[po] = &PL_sv_undef; +#endif if ((I32)po < PL_padix) PL_padix = po - 1; } @@ -1076,9 +1217,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"); @@ -1123,7 +1265,6 @@ void Perl_pad_tidy(pTHX_ padtidy_type type) { dVAR; - PADOFFSET ix; ASSERT_CURPAD_ACTIVE("pad_tidy"); @@ -1151,10 +1292,11 @@ 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 **namep = AvARRAY(PL_comppad_name); + SV * const * const namep = AvARRAY(PL_comppad_name); + PADOFFSET ix; for (ix = AvFILLp(PL_comppad); ix > 0; ix--) { SV *namesv; @@ -1166,37 +1308,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 *av = newAV(); /* Will be @_ */ - av_extend(av, 0); - av_store(PL_comppad, 0, (SV*)av); + AV * const av = newAV(); /* Will be @_ */ + 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) { - 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); @@ -1206,7 +1360,7 @@ Perl_pad_tidy(pTHX_ padtidy_type type) /* =for apidoc pad_free -Free the SV at offet po in the current pad. +Free the SV at offset po in the current pad. =cut */ @@ -1215,6 +1369,7 @@ Free the SV at offet po in the current pad. void Perl_pad_free(pTHX_ PADOFFSET po) { + dVAR; ASSERT_CURPAD_LEGAL("pad_free"); if (!PL_curpad) return; @@ -1232,13 +1387,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_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 } @@ -1259,17 +1408,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, @@ -1280,7 +1432,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)) @@ -1290,18 +1442,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) ); } @@ -1330,8 +1482,11 @@ dump the contents of a CV STATIC void S_cv_dump(pTHX_ const CV *cv, const char *title) { - const CV *outside = CvOUTSIDE(cv); - AV* padlist = CvPADLIST(cv); + 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", @@ -1374,11 +1529,11 @@ Perl_cv_clone(pTHX_ CV *proto) { dVAR; I32 ix; - AV* protopadlist = CvPADLIST(proto); - const AV* protopad_name = (AV*)*av_fetch(protopadlist, 0, FALSE); - const AV* protopad = (AV*)*av_fetch(protopadlist, 1, FALSE); - SV** pname = AvARRAY(protopad_name); - SV** ppad = AvARRAY(protopad); + AV* const protopadlist = CvPADLIST(proto); + 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); const I32 fpad = AvFILLp(protopad); CV* cv; @@ -1386,6 +1541,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 @@ -1404,14 +1561,13 @@ Perl_cv_clone(pTHX_ CV *proto) ENTER; SAVESPTR(PL_compcv); - cv = PL_compcv = (CV*)NEWSV(1104, 0); - sv_upgrade((SV *)cv, SvTYPE(proto)); + cv = PL_compcv = MUTABLE_CV(newSV_type(SvTYPE(proto))); CvFLAGS(cv) = CvFLAGS(proto) & ~(CVf_CLONE|CVf_WEAKOUTSIDE); 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 @@ -1421,11 +1577,11 @@ Perl_cv_clone(pTHX_ CV *proto) 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); @@ -1438,42 +1594,44 @@ Perl_cv_clone(pTHX_ CV *proto) outpad = AvARRAY(AvARRAY(CvPADLIST(outside))[depth]); for (ix = fpad; ix > 0; ix--) { - SV* 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; @@ -1494,10 +1652,10 @@ Perl_cv_clone(pTHX_ CV *proto) * so try to grab the current const value, and if successful, * turn into a const sub: */ - SV* const_sv = op_const_sv(CvSTART(cv), cv); + SV* const const_sv = op_const_sv(CvSTART(cv), cv); if (const_sv) { SvREFCNT_dec(cv); - cv = newCONSTSUB(CvSTASH(proto), 0, const_sv); + cv = newCONSTSUB(CvSTASH(proto), NULL, const_sv); } else { CvCONST_off(cv); @@ -1521,17 +1679,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 *comppad_name = (AV*)AvARRAY(padlist)[0]; - AV *comppad = (AV*)AvARRAY(padlist)[1]; - SV **namepad = AvARRAY(comppad_name); - SV **curpad = AvARRAY(comppad); + 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 *namesv = namepad[ix]; + const SV * const namesv = namepad[ix]; if (namesv && namesv != &PL_sv_undef && *SvPVX_const(namesv) == '&') { - CV *innercv = (CV*)curpad[ix]; + CV * const innercv = MUTABLE_CV(curpad[ix]); assert(CvWEAKOUTSIDE(innercv)); assert(CvOUTSIDE(innercv) == old_cv); CvOUTSIDE(innercv) = new_cv; @@ -1553,53 +1716,56 @@ the new pad an @_ in slot zero. void Perl_pad_push(pTHX_ PADLIST *padlist, int depth) { - if (depth <= AvFILLp(padlist)) - return; + dVAR; - { - SV** svp = AvARRAY(padlist); - AV *newpad = newAV(); - SV **oldpad = AvARRAY(svp[depth-1]); - I32 ix = AvFILLp((AV*)svp[1]); - const I32 names_fill = AvFILLp((AV*)svp[0]); - SV** names = AvARRAY(svp[0]); + 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((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 *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; } } @@ -1608,13 +1774,137 @@ Perl_pad_push(pTHX_ PADLIST *padlist, int depth) HV * Perl_pad_compname_type(pTHX_ const PADOFFSET po) { - SV** const av = av_fetch(PL_comppad_name, po, FALSE); - if ( SvFLAGS(*av) & SVpad_TYPED ) { + dVAR; + SV* const * const av = av_fetch(PL_comppad_name, po, FALSE); + 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