Iterating over the PADNAMELIST iterates over all possible pad
items. Pad slots for targets (SVs_PADTMP)
-and GVs end up having &PL_sv_undef
-"names", while slots for constants have &PL_sv_no "names" (see
-pad_alloc()). That &PL_sv_no is used is an implementation detail subject
-to change. To test for it, use C<PadnamePV(name) && !PadnameLEN(name)>.
+and GVs end up having &PL_padname_undef "names", while slots for constants
+have &PL_padname_const "names" (see pad_alloc()). That &PL_padname_undef
+and &PL_padname_const are used is an implementation detail subject to
+change. To test for them, use C<!PadnamePV(name)> and C<PadnamePV(name)
+&& !PadnameLEN(name)>, respectively.
-Only my/our variable (SvPADMY/PADNAME_isOUR) slots get valid names.
+Only my/our variable slots get valid names.
The rest are op targets/GVs/constants which are statically allocated
or resolved at compile time. These don't have names by which they
can be looked up from Perl code at run time through eval"" the way
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.
-xlow+1..xhigh inclusive in the NV union is a range of cop_seq numbers for
-which the name is valid (accessed through the macros COP_SEQ_RANGE_LOW and
-_HIGH). During compilation, these fields may hold the special value
+The pad names in the PADNAMELIST have their PV holding the name of
+the variable. The COP_SEQ_RANGE_LOW and _HIGH fields form a range
+(low+1..high inclusive) of cop_seq numbers for which the name is
+valid. During compilation, these fields may hold the special value
PERL_PADSEQ_INTRO to indicate various stages:
COP_SEQ_RANGE_LOW _HIGH
valid-seq# PERL_PADSEQ_INTRO variable in scope: { my ($x)
valid-seq# valid-seq# compilation of scope complete: { my ($x) }
-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 PADNAME_OUTER (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 xlow and xhigh to store a cop_seq range, since it is
-in scope throughout. Instead xhigh stores some flags containing info about
+For typed lexicals PadnameTYPE points at the type stash. For C<our>
+lexicals, PadnameOURSTASH points at the stash of the associated global (so
+that duplicate C<our> declarations in the same package can be detected).
+PadnameGEN is sometimes used to store the generation number during
+compilation.
+
+If PadnameOUTER is set on the pad name, then that slot in the frame AV
+is a REFCNT'ed reference to a lexical from "outside". Such entries
+are sometimes referred to as 'fake'. In this case, the name does not
+use 'low' and 'high' to store a cop_seq range, since it is in scope
+throughout. Instead 'high' 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, xlow contains the index
+instantiated multiple times?), and for fake ANONs, 'low' contains the index
within the parent's pad where the lexical's value is stored, to make
cloning quicker.
If the 'name' is '&' the corresponding entry in the PAD
is a CV representing a possible closure.
-(PADNAME_OUTER and name of '&' is not a
-meaningful combination currently but could
-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).
#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
+ STMT_START { (sv)->xpadn_low = (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
+ STMT_START { (sv)->xpadn_high = (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 PARENT_PAD_INDEX_set COP_SEQ_RANGE_LOW_set
+#define PARENT_FAKELEX_FLAGS_set COP_SEQ_RANGE_HIGH_set
#ifdef DEBUGGING
void
PadnamelistREFCNT(padname = PL_comppad_name)++;
}
else {
+ padlist->xpadl_id = PL_padlist_generation++;
av_store(pad, 0, NULL);
padname = newPADNAMELIST(0);
- padnamelist_store(padname, 0, &PL_sv_undef);
+ padnamelist_store(padname, 0, &PL_padname_undef);
}
/* Most subroutines never recurse, hence only need 2 entries in the padlist
}
/* in use, not just a prototype */
- if (inner_rc && (CvOUTSIDE(innercv) == cv)) {
+ if (inner_rc && SvTYPE(innercv) == SVt_PVCV
+ && (CvOUTSIDE(innercv) == cv))
+ {
assert(CvWEAKOUTSIDE(innercv));
/* don't relink to grandfather if he's being freed */
if (outercv && SvREFCNT(outercv)) {
}
/*
-=for apidoc m|PADOFFSET|pad_alloc_name|SV *namesv|U32 flags|HV *typestash|HV *ourstash
+=for apidoc m|PADOFFSET|pad_alloc_name|PADNAME *name|U32 flags|HV *typestash|HV *ourstash
Allocates a place in the currently-compiling
pad (via L<perlapi/pad_alloc>) and
-then stores a name for that entry. I<namesv> is adopted and becomes the
-name entry; it must already contain the name string and be sufficiently
-upgraded. I<typestash> and I<ourstash> and the C<padadd_STATE> flag get
-added to I<namesv>. None of the other
+then stores a name for that entry. I<name> is adopted and
+becomes the name entry; it must already contain the name
+string. I<typestash> and I<ourstash> and the C<padadd_STATE>
+flag get added to I<name>. None of the other
processing of L<perlapi/pad_add_name_pvn>
is done. Returns the offset of the allocated pad slot.
ASSERT_CURPAD_ACTIVE("pad_alloc_name");
if (typestash) {
- assert(SvTYPE(name) == SVt_PVMG);
SvPAD_TYPED_on(name);
- SvSTASH_set(name, MUTABLE_HV(SvREFCNT_inc_simple_NN(MUTABLE_SV(typestash))));
+ PadnameTYPE(name) =
+ MUTABLE_HV(SvREFCNT_inc_simple_NN(MUTABLE_SV(typestash)));
}
if (ourstash) {
SvPAD_OUR_on(name);
SvPAD_STATE_on(name);
}
- padnamelist_store(PL_comppad_name, offset, (SV *)name);
- PadnamelistMAXNAMED(PL_comppad_name) = offset;
+ padnamelist_store(PL_comppad_name, offset, name);
+ if (PadnameLEN(name) > 1)
+ PadnamelistMAXNAMED(PL_comppad_name) = offset;
return offset;
}
Perl_croak(aTHX_ "panic: pad_add_name_pvn illegal flag bits 0x%" UVxf,
(UV)flags);
- name = (PADNAME *)
- newSV_type((ourstash || typestash) ? SVt_PVMG : SVt_PVNV);
-
- sv_setpvn((SV *)name, namepv, namelen);
- SvUTF8_on(name);
+ name = newPADNAMEpvn(namepv, namelen);
if ((flags & padadd_NO_DUP_CHECK) == 0) {
ENTER;
- SAVEFREESV(name); /* in case of fatal warnings */
+ SAVEFREEPADNAME(name); /* in case of fatal warnings */
/* check for duplicate declaration */
pad_check_dup(name, flags & padadd_OUR, ourstash);
- SvREFCNT_inc_simple_void_NN(name);
+ PadnameREFCNT(name)++;
LEAVE;
}
break;
}
if (konst) {
- padnamelist_store(PL_comppad_name, retval, &PL_sv_no);
+ padnamelist_store(PL_comppad_name, retval, &PL_padname_const);
tmptype &= ~SVf_READONLY;
tmptype |= SVs_PADTMP;
}
Perl_pad_add_anon(pTHX_ CV* func, I32 optype)
{
PADOFFSET ix;
- SV* const name = newSV_type(SVt_PVNV);
+ PADNAME * const name = newPADNAMEpvn("&", 1);
PERL_ARGS_ASSERT_PAD_ADD_ANON;
+ assert (SvTYPE(func) == SVt_PVCV);
pad_peg("add_anon");
- sv_setpvs(name, "&");
/* These two aren't used; just make sure they're not equal to
- * PERL_PADSEQ_INTRO */
- COP_SEQ_RANGE_LOW_set(name, 0);
- COP_SEQ_RANGE_HIGH_set(name, 0);
+ * PERL_PADSEQ_INTRO. They should be 0 by default. */
+ assert(COP_SEQ_RANGE_LOW (name) != PERL_PADSEQ_INTRO);
+ assert(COP_SEQ_RANGE_HIGH(name) != PERL_PADSEQ_INTRO);
ix = pad_alloc(optype, SVs_PADMY);
padnamelist_store(PL_comppad_name, ix, name);
/* XXX DAPM use PL_curpad[] ? */
- if (SvTYPE(func) == SVt_PVCV || !CvOUTSIDE(func))
- av_store(PL_comppad, ix, (SV*)func);
- else {
- SV *rv = newRV_noinc((SV *)func);
- sv_rvweaken(rv);
- assert (SvTYPE(func) == SVt_PVFM);
- av_store(PL_comppad, ix, rv);
- }
+ av_store(PL_comppad, ix, (SV*)func);
/* to avoid ref loops, we never have parent + child referencing each
* other simultaneously */
- if (CvOUTSIDE(func) && SvTYPE(func) == SVt_PVCV) {
+ if (CvOUTSIDE(func)) {
assert(!CvWEAKOUTSIDE(func));
CvWEAKOUTSIDE_on(func);
SvREFCNT_dec_NN(CvOUTSIDE(func));
return ix;
}
+void
+Perl_pad_add_weakref(pTHX_ CV* func)
+{
+ const PADOFFSET ix = pad_alloc(OP_NULL, SVs_PADMY);
+ PADNAME * const name = newPADNAMEpvn("&", 1);
+ SV * const rv = newRV_inc((SV *)func);
+
+ PERL_ARGS_ASSERT_PAD_ADD_WEAKREF;
+
+ /* These two aren't used; just make sure they're not equal to
+ * PERL_PADSEQ_INTRO. They should be 0 by default. */
+ assert(COP_SEQ_RANGE_LOW (name) != PERL_PADSEQ_INTRO);
+ assert(COP_SEQ_RANGE_HIGH(name) != PERL_PADSEQ_INTRO);
+ padnamelist_store(PL_comppad_name, ix, name);
+ sv_rvweaken(rv);
+ av_store(PL_comppad, ix, rv);
+}
+
/*
=for apidoc pad_check_dup
vars return values, and so are pointers to where the returned values
should be stored. out_capture, if non-null, requests that the innermost
instance of the lexical is captured; out_name is set to the innermost
-matched namesv or fake namesv; out_flags returns the flags normally
-associated with the IVX field of a fake namesv.
+matched pad name or fake pad name; out_flags returns the flags normally
+associated with the PARENT_FAKELEX_FLAGS field of a fake pad name.
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 xlow the index into
+because fake names in anon protoypes have to store in xlow the index into
the parent pad.
=cut
return 0; /* this dummy (and invalid) value isnt used by the caller */
{
- /* This relies on sv_setsv_flags() upgrading the destination to the same
- type as the source, independent of the flags set, and on it being
- "good" and only copying flag bits and pointers that it understands.
- */
- PADNAME *new_name = (PADNAME *)newSVsv((SV *)*out_name);
+ PADNAME *new_name = newPADNAMEouter(*out_name);
PADNAMELIST * const ocomppad_name = PL_comppad_name;
PAD * const ocomppad = PL_comppad;
PL_comppad_name = PadlistNAMES(padlist);
PadnameOURSTASH(*out_name)
);
- SvFAKE_on(new_name);
DEBUG_Xv(PerlIO_printf(Perl_debug_log,
"Pad addname: %ld \"%.*s\" FAKE\n",
(long)new_offset,
if (PadnamelistARRAY(PL_comppad_name)[po]) {
assert(!PadnameLEN(PadnamelistARRAY(PL_comppad_name)[po]));
}
- PadnamelistARRAY(PL_comppad_name)[po] = (PADNAME *)&PL_sv_undef;
+ PadnamelistARRAY(PL_comppad_name)[po] = &PL_padname_undef;
}
/* Use PL_constpadix here, not PL_padix. The latter may have been
reset by pad_reset. We don’t want pad_alloc to have to scan the
PADNAME ** const namep = PadnamelistARRAY(PL_comppad_name);
PADOFFSET ix;
for (ix = AvFILLp(PL_comppad); ix > 0; ix--) {
- if (!namep[ix]) namep[ix] = &PL_sv_undef;
+ if (!namep[ix]) namep[ix] = &PL_padname_undef;
if (!PL_curpad[ix] || SvIMMORTAL(PL_curpad[ix]))
continue;
- if (SvPADMY(PL_curpad[ix]) && !SvFAKE(namep[ix])) {
+ if (SvPADMY(PL_curpad[ix]) && !PadnameOUTER(namep[ix])) {
/* This is a work around for how the current implementation of
?{ } blocks in regexps interacts with lexicals.
=cut
*/
-static CV *S_cv_clone(pTHX_ CV *proto, CV *cv, CV *outside);
+static CV *S_cv_clone(pTHX_ CV *proto, CV *cv, CV *outside, HV *cloned);
static CV *
-S_cv_clone_pad(pTHX_ CV *proto, CV *cv, CV *outside, bool newcv)
+S_cv_clone_pad(pTHX_ CV *proto, CV *cv, CV *outside, HV *cloned,
+ bool newcv)
{
I32 ix;
PADLIST* const protopadlist = CvPADLIST(proto);
PADNAMELIST *const protopad_name = PadlistNAMES(protopadlist);
const PAD *const protopad = PadlistARRAY(protopadlist)[1];
- SV** const pname = PadnamelistARRAY(protopad_name);
+ PADNAME** const pname = PadnamelistARRAY(protopad_name);
SV** const ppad = AvARRAY(protopad);
const I32 fname = PadnamelistMAX(protopad_name);
const I32 fpad = AvFILLp(protopad);
SV** outpad;
long depth;
- bool subclones = FALSE;
+ U32 subclones = 0;
+ bool trouble = FALSE;
assert(!CvUNIQUE(proto));
outside = CvOUTSIDE(proto);
if ((CvCLONE(outside) && ! CvCLONED(outside))
|| !CvPADLIST(outside)
- || PadlistNAMES(CvPADLIST(outside))
- != protopadlist->xpadl_outid) {
+ || CvPADLIST(outside)->xpadl_id != protopadlist->xpadl_outid) {
outside = find_runcv_where(
FIND_RUNCV_padid_eq, PTR2IV(protopadlist->xpadl_outid), NULL
);
SAVESPTR(PL_comppad_name);
PL_comppad_name = protopad_name;
CvPADLIST_set(cv, pad_new(padnew_CLONE|padnew_SAVE));
+ CvPADLIST(cv)->xpadl_id = protopadlist->xpadl_id;
av_fill(PL_comppad, fpad);
outpad = outside && CvPADLIST(outside)
? AvARRAY(PadlistARRAY(CvPADLIST(outside))[depth])
: NULL;
- if (outpad)
- CvPADLIST(cv)->xpadl_outid = PadlistNAMES(CvPADLIST(outside));
+ if (outpad) CvPADLIST(cv)->xpadl_outid = CvPADLIST(outside)->xpadl_id;
for (ix = fpad; ix > 0; ix--) {
- SV* const namesv = (ix <= fname) ? pname[ix] : NULL;
+ PADNAME* const namesv = (ix <= fname) ? pname[ix] : NULL;
SV *sv = NULL;
if (namesv && PadnameLEN(namesv)) { /* lexical */
if (PadnameIsOUR(namesv)) { /* or maybe not so lexical */
NOOP;
}
else {
- if (SvFAKE(namesv)) { /* lexical from outside? */
+ if (PadnameOUTER(namesv)) { /* lexical from outside? */
/* formats may have an inactive, or even undefined, parent;
but state vars are always available. */
if (!outpad || !(sv = outpad[PARENT_PAD_INDEX(namesv)])
SvREFCNT_inc_simple_void_NN(sv);
}
if (!sv) {
- const char sigil = SvPVX_const(namesv)[0];
+ const char sigil = PadnamePV(namesv)[0];
if (sigil == '&')
/* If there are state subs, we need to clone them, too.
But they may need to close over variables we have
second pass. */
if (SvPAD_STATE(namesv) && !CvCLONED(ppad[ix])) {
assert(SvTYPE(ppad[ix]) == SVt_PVCV);
- subclones = 1;
+ subclones ++;
+ if (CvOUTSIDE(ppad[ix]) != proto)
+ trouble = TRUE;
sv = newSV_type(SVt_PVCV);
CvLEXICAL_on(sv);
}
upgrade to the real thing on scope entry. */
dVAR;
U32 hash;
- PERL_HASH(hash, SvPVX_const(namesv)+1,
- SvCUR(namesv) - 1);
+ PERL_HASH(hash, PadnamePV(namesv)+1,
+ PadnameLEN(namesv) - 1);
sv = newSV_type(SVt_PVCV);
CvNAME_HEK_set(
sv,
- share_hek(SvPVX_const(namesv)+1,
- (SvCUR(namesv) - 1)
- * (SvUTF8(namesv) ? -1 : 1),
+ share_hek(PadnamePV(namesv)+1,
+ 1 - PadnameLEN(namesv),
hash)
);
CvLEXICAL_on(sv);
}
if (subclones)
- for (ix = fpad; ix > 0; ix--) {
- SV* const namesv = (ix <= fname) ? pname[ix] : NULL;
- if (namesv && namesv != &PL_sv_undef && !SvFAKE(namesv)
- && SvPVX_const(namesv)[0] == '&' && SvPAD_STATE(namesv))
- S_cv_clone(aTHX_ (CV *)ppad[ix], (CV *)PL_curpad[ix], cv);
+ {
+ if (trouble || cloned) {
+ /* Uh-oh, we have trouble! At least one of the state subs here
+ has its CvOUTSIDE pointer pointing somewhere unexpected. It
+ could be pointing to another state protosub that we are
+ about to clone. So we have to track which sub clones come
+ from which protosubs. If the CvOUTSIDE pointer for a parti-
+ cular sub points to something we have not cloned yet, we
+ delay cloning it. We must loop through the pad entries,
+ until we get a full pass with no cloning. If any uncloned
+ subs remain (probably nested inside anonymous or ‘my’ subs),
+ then they get cloned in a final pass.
+ */
+ bool cloned_in_this_pass;
+ if (!cloned)
+ cloned = (HV *)sv_2mortal((SV *)newHV());
+ do {
+ cloned_in_this_pass = FALSE;
+ for (ix = fpad; ix > 0; ix--) {
+ PADNAME * const name =
+ (ix <= fname) ? pname[ix] : NULL;
+ if (name && name != &PL_padname_undef
+ && !PadnameOUTER(name) && PadnamePV(name)[0] == '&'
+ && PadnameIsSTATE(name) && !CvCLONED(PL_curpad[ix]))
+ {
+ CV * const protokey = CvOUTSIDE(ppad[ix]);
+ CV ** const cvp = protokey == proto
+ ? &cv
+ : (CV **)hv_fetch(cloned, (char *)&protokey,
+ sizeof(CV *), 0);
+ if (cvp && *cvp) {
+ S_cv_clone(aTHX_ (CV *)ppad[ix],
+ (CV *)PL_curpad[ix],
+ *cvp, cloned);
+ hv_store(cloned, (char *)&ppad[ix],
+ sizeof(CV *),
+ SvREFCNT_inc_simple_NN(PL_curpad[ix]),
+ 0);
+ subclones--;
+ cloned_in_this_pass = TRUE;
+ }
+ }
+ }
+ } while (cloned_in_this_pass);
+ if (subclones)
+ for (ix = fpad; ix > 0; ix--) {
+ PADNAME * const name =
+ (ix <= fname) ? pname[ix] : NULL;
+ if (name && name != &PL_padname_undef
+ && !PadnameOUTER(name) && PadnamePV(name)[0] == '&'
+ && PadnameIsSTATE(name) && !CvCLONED(PL_curpad[ix]))
+ S_cv_clone(aTHX_ (CV *)ppad[ix],
+ (CV *)PL_curpad[ix],
+ CvOUTSIDE(ppad[ix]), cloned);
+ }
+ }
+ else for (ix = fpad; ix > 0; ix--) {
+ PADNAME * const name = (ix <= fname) ? pname[ix] : NULL;
+ if (name && name != &PL_padname_undef && !PadnameOUTER(name)
+ && PadnamePV(name)[0] == '&' && PadnameIsSTATE(name))
+ S_cv_clone(aTHX_ (CV *)ppad[ix], (CV *)PL_curpad[ix], cv,
+ NULL);
}
+ }
if (newcv) SvREFCNT_inc_simple_void_NN(cv);
LEAVE;
nextstate
padsv
*/
- if (OP_SIBLING(
+ if (OpSIBLING(
cUNOPx(cUNOPx(CvROOT(cv))->op_first)->op_first
) == o
- && !OP_SIBLING(o))
+ && !OpSIBLING(o))
{
Perl_ck_warner_d(aTHX_
packWARN(WARN_DEPRECATED),
}
static CV *
-S_cv_clone(pTHX_ CV *proto, CV *cv, CV *outside)
+S_cv_clone(pTHX_ CV *proto, CV *cv, CV *outside, HV *cloned)
{
#ifdef USE_ITHREADS
dVAR;
mg_copy((SV *)proto, (SV *)cv, 0, 0);
if (CvPADLIST(proto))
- cv = S_cv_clone_pad(aTHX_ proto, cv, outside, newcv);
+ cv = S_cv_clone_pad(aTHX_ proto, cv, outside, cloned, newcv);
DEBUG_Xv(
PerlIO_printf(Perl_debug_log, "\nPad CV clone\n");
PERL_ARGS_ASSERT_CV_CLONE;
if (!CvPADLIST(proto)) Perl_croak(aTHX_ "panic: no pad in cv_clone");
- return S_cv_clone(aTHX_ proto, NULL, NULL);
+ return S_cv_clone(aTHX_ proto, NULL, NULL, NULL);
}
/* Called only by pp_clonecv */
{
PERL_ARGS_ASSERT_CV_CLONE_INTO;
cv_undef(target);
- return S_cv_clone(aTHX_ proto, target, NULL);
+ return S_cv_clone(aTHX_ proto, target, NULL, NULL);
}
/*
I32 ix;
PADNAMELIST * const comppad_name = PadlistNAMES(padlist);
AV * const comppad = PadlistARRAY(padlist)[1];
- SV ** const namepad = PadnamelistARRAY(comppad_name);
+ PADNAME ** const namepad = PadnamelistARRAY(comppad_name);
SV ** const curpad = AvARRAY(comppad);
PERL_ARGS_ASSERT_PAD_FIXUP_INNER_ANONS;
PERL_UNUSED_ARG(old_cv);
for (ix = PadnamelistMAX(comppad_name); ix > 0; ix--) {
- const SV * const namesv = namepad[ix];
- if (namesv && namesv != &PL_sv_undef && !SvPAD_STATE(namesv)
- && *SvPVX_const(namesv) == '&')
+ const PADNAME *name = namepad[ix];
+ if (name && name != &PL_padname_undef && !PadnameIsOUR(name)
+ && *PadnamePV(name) == '&')
{
- if (SvTYPE(curpad[ix]) == SVt_PVCV) {
- MAGIC * const mg =
- SvMAGICAL(curpad[ix])
- ? mg_find(curpad[ix], PERL_MAGIC_proto)
- : NULL;
- CV * const innercv = MUTABLE_CV(mg ? mg->mg_obj : curpad[ix]);
+ CV *innercv = MUTABLE_CV(curpad[ix]);
+ if (UNLIKELY(PadnameOUTER(name))) {
+ CV *cv = new_cv;
+ PADNAME **names = namepad;
+ PADOFFSET i = ix;
+ while (PadnameOUTER(name)) {
+ cv = CvOUTSIDE(cv);
+ names = PadlistNAMESARRAY(CvPADLIST(cv));
+ i = PARENT_PAD_INDEX(name);
+ name = names[i];
+ }
+ innercv = (CV *)PadARRAY(PadlistARRAY(CvPADLIST(cv))[1])[i];
+ }
+ if (SvTYPE(innercv) == SVt_PVCV) {
+ /* XXX 0afba48f added code here to check for a proto CV
+ attached to the pad entry by magic. But shortly there-
+ after 81df9f6f95 moved the magic to the pad name. The
+ code here was never updated, so it wasn’t doing anything
+ and got deleted when PADNAME became a distinct type. Is
+ there any bug as a result? */
if (CvOUTSIDE(innercv) == old_cv) {
if (!CvWEAKOUTSIDE(innercv)) {
SvREFCNT_dec(old_cv);
SV** const oldpad = AvARRAY(svp[depth-1]);
I32 ix = AvFILLp((const AV *)svp[1]);
const I32 names_fill = PadnamelistMAX((PADNAMELIST *)svp[0]);
- SV** const names = PadnamelistARRAY((PADNAMELIST *)svp[0]);
+ PADNAME ** const names = PadnamelistARRAY((PADNAMELIST *)svp[0]);
AV *av;
for ( ;ix > 0; ix--) {
if (names_fill >= ix && PadnameLEN(names[ix])) {
- const char sigil = SvPVX_const(names[ix])[0];
- if ((SvFLAGS(names[ix]) & SVf_FAKE)
- || (SvFLAGS(names[ix]) & SVpad_STATE)
+ const char sigil = PadnamePV(names[ix])[0];
+ if (PadnameOUTER(names[ix])
+ || PadnameIsSTATE(names[ix])
|| sigil == '&')
{
/* outer lexical or anon code */
PERL_ARGS_ASSERT_PADLIST_DUP;
- cloneall = param->flags & CLONEf_COPY_STACKS;
+ cloneall = cBOOL(param->flags & CLONEf_COPY_STACKS);
assert (SvREFCNT(PadlistARRAY(srcpad)[1]) == 1);
max = cloneall ? PadlistMAX(srcpad) : 1;
const I32 names_fill = PadnamelistMAX(PadlistNAMES(srcpad));
const PAD *const srcpad1 = PadlistARRAY(srcpad)[1];
SV **oldpad = AvARRAY(srcpad1);
- SV ** const names = PadnamelistARRAY(PadlistNAMES(dstpad));
+ PADNAME ** const names = PadnamelistARRAY(PadlistNAMES(dstpad));
SV **pad1a;
AV *args;
pad1a[ix] = NULL;
} else if (names_fill >= ix && names[ix] &&
PadnameLEN(names[ix])) {
- const char sigil = SvPVX_const(names[ix])[0];
- if ((SvFLAGS(names[ix]) & SVf_FAKE)
- || (SvFLAGS(names[ix]) & SVpad_STATE)
+ const char sigil = PadnamePV(names[ix])[0];
+ if (PadnameOUTER(names[ix])
+ || PadnameIsSTATE(names[ix])
|| sigil == '&')
{
/* outer lexical or anon code */
*/
PADNAMELIST *
-Perl_newPADNAMELIST(pTHX_ size_t max)
+Perl_newPADNAMELIST(size_t max)
{
PADNAMELIST *pnl;
Newx(pnl, 1, PADNAMELIST);
PadnamelistMAX(pnl) = key;
}
ary = PadnamelistARRAY(pnl);
- SvREFCNT_dec(ary[key]);
+ if (ary[key])
+ PadnameREFCNT_dec(ary[key]);
ary[key] = val;
return &ary[key];
}
*/
PADNAME *
-Perl_padnamelist_fetch(pTHX_ PADNAMELIST *pnl, SSize_t key)
+Perl_padnamelist_fetch(PADNAMELIST *pnl, SSize_t key)
{
PERL_ARGS_ASSERT_PADNAMELIST_FETCH;
ASSUME(key >= 0);
PERL_ARGS_ASSERT_PADNAMELIST_FREE;
if (!--PadnamelistREFCNT(pnl)) {
while(PadnamelistMAX(pnl) >= 0)
- SvREFCNT_dec(PadnamelistARRAY(pnl)[PadnamelistMAX(pnl)--]);
+ {
+ PADNAME * const pn =
+ PadnamelistARRAY(pnl)[PadnamelistMAX(pnl)--];
+ if (pn)
+ PadnameREFCNT_dec(pn);
+ }
Safefree(PadnamelistARRAY(pnl));
Safefree(pnl);
}
ptr_table_store(PL_ptr_table, srcpad, dstpad);
for (; max >= 0; max--)
+ if (PadnamelistARRAY(srcpad)[max]) {
PadnamelistARRAY(dstpad)[max] =
- sv_dup_inc(PadnamelistARRAY(srcpad)[max], param);
+ padname_dup(PadnamelistARRAY(srcpad)[max], param);
+ PadnameREFCNT(PadnamelistARRAY(dstpad)[max])++;
+ }
return dstpad;
}
#endif /* USE_ITHREADS */
+/*
+=for apidoc newPADNAMEpvn
+
+Constructs and returns a new pad name. I<s> must be a UTF8 string. Do not
+use this for pad names that point to outer lexicals. See
+L</newPADNAMEouter>.
+
+=cut
+*/
+
+PADNAME *
+Perl_newPADNAMEpvn(const char *s, STRLEN len)
+{
+ struct padname_with_str *alloc;
+ char *alloc2; /* for Newxz */
+ PADNAME *pn;
+ PERL_ARGS_ASSERT_NEWPADNAMEPVN;
+ Newxz(alloc2,
+ STRUCT_OFFSET(struct padname_with_str, xpadn_str[0]) + len + 1,
+ char);
+ alloc = (struct padname_with_str *)alloc2;
+ pn = (PADNAME *)alloc;
+ PadnameREFCNT(pn) = 1;
+ PadnamePV(pn) = alloc->xpadn_str;
+ Copy(s, PadnamePV(pn), len, char);
+ *(PadnamePV(pn) + len) = '\0';
+ PadnameLEN(pn) = len;
+ return pn;
+}
+
+/*
+=for apidoc newPADNAMEouter
+
+Constructs and returns a new pad name. Only use this function for names
+that refer to outer lexicals. (See also L</newPADNAMEpvn>.) I<outer> is
+the outer pad name that this one mirrors. The returned pad name has the
+PADNAMEt_OUTER flag already set.
+
+=cut
+*/
+
+PADNAME *
+Perl_newPADNAMEouter(PADNAME *outer)
+{
+ PADNAME *pn;
+ PERL_ARGS_ASSERT_NEWPADNAMEOUTER;
+ Newxz(pn, 1, PADNAME);
+ PadnameREFCNT(pn) = 1;
+ PadnamePV(pn) = PadnamePV(outer);
+ /* Not PadnameREFCNT(outer), because ‘outer’ may itself close over
+ another entry. The original pad name owns the buffer. */
+ PadnameREFCNT(PADNAME_FROM_PV(PadnamePV(outer)))++;
+ PadnameFLAGS(pn) = PADNAMEt_OUTER;
+ PadnameLEN(pn) = PadnameLEN(outer);
+ return pn;
+}
+
+void
+Perl_padname_free(pTHX_ PADNAME *pn)
+{
+ PERL_ARGS_ASSERT_PADNAME_FREE;
+ if (!--PadnameREFCNT(pn)) {
+ if (UNLIKELY(pn == &PL_padname_undef || pn == &PL_padname_const)) {
+ PadnameREFCNT(pn) = SvREFCNT_IMMORTAL;
+ return;
+ }
+ SvREFCNT_dec(PadnameTYPE(pn)); /* Takes care of protocv, too. */
+ SvREFCNT_dec(PadnameOURSTASH(pn));
+ if (PadnameOUTER(pn))
+ PadnameREFCNT_dec(PADNAME_FROM_PV(PadnamePV(pn)));
+ Safefree(pn);
+ }
+}
+
+#if defined(USE_ITHREADS)
+
+/*
+=for apidoc padname_dup
+
+Duplicates a pad name.
+
+=cut
+*/
+
+PADNAME *
+Perl_padname_dup(pTHX_ PADNAME *src, CLONE_PARAMS *param)
+{
+ PADNAME *dst;
+
+ PERL_ARGS_ASSERT_PADNAME_DUP;
+
+ /* look for it in the table first */
+ dst = (PADNAME *)ptr_table_fetch(PL_ptr_table, src);
+ if (dst)
+ return dst;
+
+ if (!PadnamePV(src)) {
+ dst = &PL_padname_undef;
+ ptr_table_store(PL_ptr_table, src, dst);
+ return dst;
+ }
+
+ dst = PadnameOUTER(src)
+ ? newPADNAMEouter(padname_dup(PADNAME_FROM_PV(PadnamePV(src)), param))
+ : newPADNAMEpvn(PadnamePV(src), PadnameLEN(src));
+ ptr_table_store(PL_ptr_table, src, dst);
+ PadnameLEN(dst) = PadnameLEN(src);
+ PadnameFLAGS(dst) = PadnameFLAGS(src);
+ PadnameREFCNT(dst) = 0; /* The caller will increment it. */
+ PadnameTYPE (dst) = (HV *)sv_dup_inc((SV *)PadnameTYPE(src), param);
+ PadnameOURSTASH(dst) = (HV *)sv_dup_inc((SV *)PadnameOURSTASH(src),
+ param);
+ dst->xpadn_low = src->xpadn_low;
+ dst->xpadn_high = src->xpadn_high;
+ dst->xpadn_gen = src->xpadn_gen;
+ return dst;
+}
+
+#endif /* USE_ITHREADS */
/*
* Local variables: