Fixed by attached patch.
--
Paul Evans
=== modified file 'Build.PL'
--- old/Build.PL 2020-03-18 17:51:49 +0000
+++ new/Build.PL 2020-03-25 19:12:24 +0000
@@ -14,6 +14,7 @@
test_requires => {
'Data::Dump' => 0,
'Test::More' => '0.88', # done_testing
+ 'Test::Refcount' => 0,
},
configure_requires => {
'Module::Build' => '0.4004', # test_requires
=== modified file 'lib/Object/Pad.xs'
--- old/lib/Object/Pad.xs 2020-03-20 22:21:32 +0000
+++ new/lib/Object/Pad.xs 2020-03-25 19:12:24 +0000
@@ -172,10 +172,11 @@
PADIX_SLOTS = 2,
};
-static OP *newPADSVOP(PADOFFSET padix, I32 flags)
+static OP *newPADSVOP(PADOFFSET padix, I32 flags, U32 private)
{
OP *op = newOP(OP_PADSV, flags);
op->op_targ = padix;
+ op->op_private = private;
return op;
}
@@ -192,6 +193,7 @@
if(!sv_derived_from(self, HvNAME(classstash)))
croak("Cannot invoke foreign method on non-derived instance");
+ save_clearsv(&PAD_SVl(PADIX_SELF));
sv_setsv(PAD_SVl(PADIX_SELF), self);
SV *slotsav;
@@ -216,7 +218,8 @@
}
}
- PAD_SVl(PADIX_SLOTS) = slotsav;
+ save_clearsv(&PAD_SVl(PADIX_SLOTS));
+ PAD_SVl(PADIX_SLOTS) = SvREFCNT_inc(slotsav);
return PL_op->op_next;
}
@@ -390,7 +393,8 @@
ops = op_append_list(OP_LINESEQ, ops,
/* $self = shift */
- newBINOP(OP_SASSIGN, 0, newOP(OP_SHIFT, 0), newPADSVOP(PADIX_SELF, OPf_MOD)));
+ newBINOP(OP_SASSIGN, 0, newOP(OP_SHIFT, 0),
+ newPADSVOP(PADIX_SELF, OPf_MOD, OPpLVAL_INTRO)));
intro_my();
@@ -404,7 +408,7 @@
/* Build an OP_ENTERSUB for $self->SUPER::INITSLOTS() */
OP *op = NULL;
op = op_append_list(OP_LIST, op,
- newPADSVOP(PADIX_SELF, 0));
+ newPADSVOP(PADIX_SELF, 0, 0));
op = op_append_list(OP_LIST, op,
newMETHOD_REDIR_OP(superclass, newSVpvn_share("INITSLOTS", 9, 0), 0));
@@ -424,13 +428,13 @@
switch(meta->repr) {
case REPR_NATIVE:
/* $self->@* */
- slotsavop = newUNOP(OP_RV2AV, OPf_MOD|OPf_REF, newPADSVOP(PADIX_SELF, 0));
+ slotsavop = newUNOP(OP_RV2AV, OPf_MOD|OPf_REF, newPADSVOP(PADIX_SELF, 0, 0));
break;
case REPR_FOREIGN_HASH:
/* $self->{"Object::Pad/slots"}->@* */
slotsavop = newUNOP(OP_RV2AV, OPf_MOD|OPf_REF,
newBINOP(OP_HELEM, OPf_MOD,
- newUNOP(OP_RV2HV, OPf_MOD|OPf_REF, newPADSVOP(PADIX_SELF, 0)),
+ newUNOP(OP_RV2HV, OPf_MOD|OPf_REF, newPADSVOP(PADIX_SELF, 0, 0)),
newSVOP(OP_CONST, 0, newSVpvs("Object::Pad/slots"))));
break;
}
@@ -514,7 +518,7 @@
switch(meta->repr) {
case REPR_NATIVE:
CopLINE_set(PL_curcop, __LINE__);
- self = newRV_noinc((SV *)newAV());
+ self = sv_2mortal(newRV_noinc((SV *)newAV()));
sv_bless(self, meta->stash);
break;
=== modified file 't/03create.t'
--- old/t/03create.t 2019-11-19 12:03:22 +0000
+++ new/t/03create.t 2020-03-25 19:12:24 +0000
@@ -4,6 +4,7 @@
use warnings;
use Test::More;
+use Test::Refcount;
use Object::Pad;
@@ -20,7 +21,10 @@
{
my $p = Point->new( 10, 20 );
+ is_oneref( $p, '$p has refcount 1 initially' );
+
is( $p->where, "(10,20)", '$p->where' );
+ is_oneref( $p, '$p has refcount 1 after method' );
}
done_testing;
=== modified file 't/80async-method.t'
--- old/t/80async-method.t 2020-03-24 16:10:03 +0000
+++ new/t/80async-method.t 2020-03-25 19:12:24 +0000
@@ -4,6 +4,7 @@
use warnings;
use Test::More;
+use Test::Refcount;
BEGIN {
plan skip_all => "Future is not available"
@@ -38,14 +39,19 @@
}
my $thunker = Thunker->new;
+ is_oneref( $thunker, 'after ->new' );
my $f1 = Future->new;
my $fret = $thunker->thunk( $f1 );
+ is_refcount( $thunker, 3, 'during async sub' );
+ # +1 because $self, +1 because of @(Object::Pad/slots) pseudolexical
is( $thunker->count, 0, 'count is 0 before $f1->done' );
$f1->done;
+ is_oneref( $thunker, 'after ->done' );
+
is( $thunker->count, 1, 'count is 1 after $f1->done' );
is( $fret->get, "result", '$fret for await in async method' );
}