valid. During compilation, these fields may hold the special value
PERL_PADSEQ_INTRO to indicate various stages:
- COP_SEQ_RANGE_LOW _HIGH
- ----------------- -----
- PERL_PADSEQ_INTRO 0 variable not yet introduced: { my ($x
- valid-seq# PERL_PADSEQ_INTRO variable in scope: { my ($x)
- valid-seq# valid-seq# compilation of scope complete: { my ($x) }
+ COP_SEQ_RANGE_LOW _HIGH
+ ----------------- -----
+ PERL_PADSEQ_INTRO 0 variable not yet introduced:
+ { my ($x
+ valid-seq# PERL_PADSEQ_INTRO variable in scope:
+ { my ($x)
+ valid-seq# valid-seq# compilation of scope complete:
+ { my ($x) }
For typed lexicals PadnameTYPE points at the type stash. For C<our>
lexicals, PadnameOURSTASH points at the stash of the associated global (so
# if PTRSIZE == 8
assert((Size_t)padlist != UINT64_C(0xEFEFEFEFEFEFEFEF));
# elif PTRSIZE == 4
- assert((Size_t)padlist != UINT64_C(0xEFEFEFEF));
+ assert((Size_t)padlist != 0xEFEFEFEF);
# else
# error unknown pointer size
# endif
void
Perl_cv_forget_slab(pTHX_ CV *cv)
{
- const bool slabbed = !!CvSLABBED(cv);
+ bool slabbed;
OPSLAB *slab = NULL;
- PERL_ARGS_ASSERT_CV_FORGET_SLAB;
-
+ if (!cv)
+ return;
+ slabbed = cBOOL(CvSLABBED(cv));
if (!slabbed) return;
CvSLABBED_off(cv);
Allocates a place in the currently-compiling
pad (via L<perlapi/pad_alloc>) and
-then stores a name for that entry. I<name> is adopted and
+then stores a name for that entry. C<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
+string. C<typestash> and C<ourstash> and the C<padadd_STATE>
+flag get added to C<name>. None of the other
processing of L<perlapi/pad_add_name_pvn>
is done. Returns the offset of the allocated pad slot.
pad, and makes preparations to manage the variable's lexical scoping.
Returns the offset of the allocated pad slot.
-I<namepv>/I<namelen> specify the variable's name, including leading sigil.
-If I<typestash> is non-null, the name is for a typed lexical, and this
-identifies the type. If I<ourstash> is non-null, it's a lexical reference
+C<namepv>/C<namelen> specify the variable's name, including leading sigil.
+If C<typestash> is non-null, the name is for a typed lexical, and this
+identifies the type. If C<ourstash> is non-null, it's a lexical reference
to a package variable, and this identifies the package. The following
flags can be OR'ed together:
- padadd_OUR redundantly specifies if it's a package var
- padadd_STATE variable will retain value persistently
- padadd_NO_DUP_CHECK skip check for lexical shadowing
+ padadd_OUR redundantly specifies if it's a package var
+ padadd_STATE variable will retain value persistently
+ padadd_NO_DUP_CHECK skip check for lexical shadowing
=cut
*/
Allocates a place in the currently-compiling pad,
returning the offset of the allocated pad slot.
No name is initially attached to the pad slot.
-I<tmptype> is a set of flags indicating the kind of pad entry required,
+C<tmptype> is a set of flags indicating the kind of pad entry required,
which will be set in the value SV for the allocated pad entry:
SVs_PADMY named lexical variable ("my", "our", "state")
tells C<pad_alloc> that it I<will> be made read-only (by the caller), or at
least should be treated as such.
-I<optype> should be an opcode indicating the type of operation that the
+C<optype> should be an opcode indicating the type of operation that the
pad entry is to support. This doesn't affect operational semantics,
but is used for debugging.
Allocates a place in the currently-compiling pad (via L</pad_alloc>)
for an anonymous function that is lexically scoped inside the
currently-compiling function.
-The function I<func> is linked into the pad, and its C<CvOUTSIDE> link
+The function C<func> is linked into the pad, and its C<CvOUTSIDE> link
to the outer scope is weakened to avoid a reference loop.
One reference count is stolen, so you may need to do C<SvREFCNT_inc(func)>.
-I<optype> should be an opcode indicating the type of operation that the
+C<optype> should be an opcode indicating the type of operation that the
pad entry is to support. This doesn't affect operational semantics,
but is used for debugging.
Given the name of a lexical variable, find its position in the
currently-compiling pad.
-I<namepv>/I<namelen> specify the variable's name, including leading sigil.
-I<flags> is reserved and must be zero.
+C<namepv>/C<namelen> specify the variable's name, including leading sigil.
+C<flags> is reserved and must be zero.
If it is not in the current pad but appears in the pad of any lexically
enclosing scope, then a pseudo-entry for it is added in the current pad.
Returns the offset in the current pad,
Perl_croak(aTHX_ "panic: pad_findmy_pvn illegal flag bits 0x%" UVxf,
(UV)flags);
+ /* compilation errors can zero PL_compcv */
+ if (!PL_compcv)
+ return NOT_IN_PAD;
+
offset = pad_findlex(namepv, namelen, flags,
PL_compcv, PL_cop_seqmax, 1, NULL, &out_pn, &out_flags);
if ((PADOFFSET)offset != NOT_IN_PAD)
/*
=for apidoc Am|SV *|pad_sv|PADOFFSET po
-Get the value at offset I<po> in the current (compiling or executing) pad.
+Get the value at offset C<po> in the current (compiling or executing) pad.
Use macro PAD_SV instead of calling this function directly.
=cut
/*
=for apidoc Am|void|pad_setsv|PADOFFSET po|SV *sv
-Set the value at offset I<po> in the current (compiling or executing) pad.
+Set the value at offset C<po> in the current (compiling or executing) pad.
Use the macro PAD_SETSV() rather than calling this function directly.
=cut
Tidy up a pad at the end of compilation of the code to which it belongs.
Jobs performed here are: remove most stuff from the pads of anonsub
-prototypes; give it a @_; mark temporaries as such. I<type> indicates
+prototypes; give it a @_; mark temporaries as such. C<type> indicates
the kind of subroutine:
padtidy_SUB ordinary subroutine
/*
=for apidoc Am|CV *|cv_clone|CV *proto
-Clone a CV, making a lexical closure. I<proto> supplies the prototype
+Clone a CV, making a lexical closure. C<proto> supplies the prototype
of the function: its code, pad structure, and other attributes.
The prototype is combined with a capture of outer lexicals to which the
code refers, which are taken from the currently-executing instance of
=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);
const I32 fpad = AvFILLp(protopad);
SV** outpad;
long depth;
- bool subclones = FALSE;
+ U32 subclones = 0;
+ bool trouble = FALSE;
assert(!CvUNIQUE(proto));
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);
}
}
if (subclones)
- for (ix = fpad; ix > 0; ix--) {
+ {
+ 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);
+ (void)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);
+ S_cv_clone(aTHX_ (CV *)ppad[ix], (CV *)PL_curpad[ix], cv,
+ NULL);
}
+ }
if (newcv) SvREFCNT_inc_simple_void_NN(cv);
LEAVE;
}
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);
}
/*
to it and it will be returned. Otherwise the returned SV will be a new
mortal.
-If the I<flags> include CV_NAME_NOTQUAL, then the package name will not be
+If the C<flags> include CV_NAME_NOTQUAL, then the package name will not be
included. If the first argument is neither a CV nor a GV, this flag is
ignored (subject to change).
/*
=for apidoc newPADNAMEpvn
-Constructs and returns a new pad name. I<s> must be a UTF8 string. Do not
+Constructs and returns a new pad name. C<s> must be a UTF8 string. Do not
use this for pad names that point to outer lexicals. See
L</newPADNAMEouter>.
=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
+that refer to outer lexicals. (See also L</newPADNAMEpvn>.) C<outer> is
the outer pad name that this one mirrors. The returned pad name has the
PADNAMEt_OUTER flag already set.
#endif /* USE_ITHREADS */
/*
- * Local variables:
- * c-indentation-style: bsd
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
* ex: set ts=8 sts=4 sw=4 et:
*/