summaryrefslogtreecommitdiff
path: root/pad.c
diff options
context:
space:
mode:
authorFather Chrysostomos <sprout@cpan.org>2012-09-10 21:59:51 -0700
committerFather Chrysostomos <sprout@cpan.org>2012-09-15 22:45:09 -0700
commit81df9f6f95225e40ead5e853dadb0bb98be2531b (patch)
tree422e6242902659e264962b28b8417a89665a1451 /pad.c
parentd2c8bf052f5a8bb99050f6d2418d77151eb4b468 (diff)
downloadperl-81df9f6f95225e40ead5e853dadb0bb98be2531b.tar.gz
Move my sub prototype CVs to the pad names
my subs are cloned on scope entry. To make closures work, a stub stored in the pad (and closed over elsewhere) is cloned into. But we need somewhere to store the prototype from which the clone is made. I was attaching the prototype via magic to the stub in the pad, since the pad is available at run time, but not the pad names. That leads to lots of little games all over the place to make sure the prototype isn’t lost when the pad is swiped on scope exit (SAVEt_CLEARSV in scope.c). We also run the risk of losing it if an XS module replaces the sub with another. Instead, we should be storing it with the pad name. The previous com- mit made the pad names available at run time, so we can move it there (still stuffed inside a magic box) and delete much code. This does mean that newMYSUB cannot rely on the behaviour of non-clon- able subs that close over variables (or subs) immediately. Previ- ously, we would dig through outer scopes to find the stub in cases like this: sub y { my sub foo; sub x { sub { sub foo { ... } } } } We would stop at x, which happens to have y’s stub in its pad, so that’s no problem. If we attach it to the pad name, we definitely have to dig past x to get to the pad name in y’s pad. Usually, immediate closures do not store the parent pad index, since it will never be used. But now we do need to use it, so we modify the code in pad.c:S_pad_findlex to set it always for my/state.
Diffstat (limited to 'pad.c')
-rw-r--r--pad.c26
1 files changed, 5 insertions, 21 deletions
diff --git a/pad.c b/pad.c
index 2d14810d0a..e25d06d7eb 100644
--- a/pad.c
+++ b/pad.c
@@ -1383,6 +1383,8 @@ S_pad_findlex(pTHX_ const char *namepv, STRLEN namelen, U32 flags, const CV* cv,
else {
/* immediate creation - capture outer value right now */
av_store(PL_comppad, new_offset, SvREFCNT_inc(*new_capturep));
+ /* But also note the offset, as newMYSUB needs it */
+ PARENT_PAD_INDEX_set(new_namesv, offset);
DEBUG_Xv(PerlIO_printf(Perl_debug_log,
"Pad findlex cv=0x%"UVxf" saved captured sv 0x%"UVxf" at offset %ld\n",
PTR2UV(cv), PTR2UV(*new_capturep), (long)new_offset));
@@ -2059,26 +2061,9 @@ S_cv_clone_pad(pTHX_ CV *proto, CV *cv, CV *outside)
else if (PadnameLEN(namesv)>1 && !PadnameIsOUR(namesv))
{
/* my sub */
- sv = newSV_type(SVt_PVCV);
- if (SvTYPE(ppad[ix]) == SVt_PVCV) {
- /* This is actually a stub with a proto CV attached
- to it by magic. Since the stub itself is used
- when the proto is cloned, we need a new stub
- that nonetheless shares the same proto.
- */
- MAGIC * const mg =
- mg_find(ppad[ix], PERL_MAGIC_proto);
- assert(mg);
- assert(mg->mg_obj);
- assert(SvTYPE(ppad[ix]) == SVt_PVCV);
- assert(CvNAME_HEK((CV *)ppad[ix]));
- CvNAME_HEK_set(sv,
- share_hek_hek(CvNAME_HEK((CV *)ppad[ix])));
- sv_magic(sv,mg->mg_obj,PERL_MAGIC_proto,NULL,0);
- }
- else {
- assert(SvTYPE(ppad[ix]) == SVt_NULL);
- /* Unavailable; just provide a stub, but name it */
+ /* Just provide a stub, but name it. It will be
+ upgrade to the real thing on scope entry. */
+ sv = newSV_type(SVt_PVCV);
CvNAME_HEK_set(
sv,
share_hek(SvPVX_const(namesv)+1,
@@ -2086,7 +2071,6 @@ S_cv_clone_pad(pTHX_ CV *proto, CV *cv, CV *outside)
* (SvUTF8(namesv) ? -1 : 1),
0)
);
- }
}
else sv = SvREFCNT_inc(ppad[ix]);
else if (sigil == '@')