Skip to content

Commit 2899bb2

Browse files
committed
support RC XS subs: add CVf_XS_RCSTACK flag
Allow an XS sub to be flagged with CVf_XS_RCSTACK, which indicates that it expects a reference-counted stack - and so pp_entersub() etc should invoke it directly rather than via xs_wrap() on PERL_RC_STACK builds. Note that there is not yet any syntax in an XS file which supports marking an XS sub as 'RC-aware', so this facility is very much in the early stages and "at your own risk", requiring the CV to manually have its CVf_XS_RCSTACK flag set.
1 parent 02a9756 commit 2899bb2

File tree

5 files changed

+92
-3
lines changed

5 files changed

+92
-3
lines changed

MANIFEST

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4897,6 +4897,7 @@ ext/XS-APItest/t/ptr_table.t Test ptr_table_* APIs
48974897
ext/XS-APItest/t/push.t XS::APItest extension
48984898
ext/XS-APItest/t/refs.t Test typemap ref handling
48994899
ext/XS-APItest/t/rmagical.t XS::APItest extension
4900+
ext/XS-APItest/t/rpp_invoke_xs.t XS::APItest: test rpp_invoke_xs()
49004901
ext/XS-APItest/t/rv2cv_op_cv.t test rv2cv_op_cv() API
49014902
ext/XS-APItest/t/savehints.t test SAVEHINTS() API
49024903
ext/XS-APItest/t/savestack.t test savestack behavior, currently only in the regex engine

cv.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ See L<perlguts/Autoloading with XSUBs>.
138138
#define CVf_IsMETHOD 0x100000 /* CV is a (real) method of a real class. Not
139139
to be confused with what used to be called
140140
CVf_METHOD; now CVf_NOWARN_AMBIGUOUS */
141+
#define CVf_XS_RCSTACK 0x200000 /* the XS function understands a
142+
reference-counted stack */
141143

142144
/* This symbol for optimised communication between toke.c and op.c: */
143145
#define CVf_BUILTIN_ATTRS (CVf_NOWARN_AMBIGUOUS|CVf_LVALUE|CVf_ANONCONST)
@@ -264,6 +266,10 @@ Helper macro to turn off the C<CvREFCOUNTED_ANYSV> flag.
264266
#define CvIsMETHOD_on(cv) (CvFLAGS(cv) |= CVf_IsMETHOD)
265267
#define CvIsMETHOD_off(cv) (CvFLAGS(cv) &= ~CVf_IsMETHOD)
266268

269+
#define CvXS_RCSTACK(cv) (CvFLAGS(cv) & CVf_XS_RCSTACK)
270+
#define CvXS_RCSTACK_on(cv) (CvFLAGS(cv) |= CVf_XS_RCSTACK)
271+
#define CvXS_RCSTACK_off(cv) (CvFLAGS(cv) &= ~CVf_XS_RCSTACK)
272+
267273
/* Back-compat */
268274
#ifndef PERL_CORE
269275
# define CVf_METHOD CVf_NOWARN_AMBIGUOUS

ext/XS-APItest/APItest.xs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4821,6 +4821,35 @@ set_custom_pp_func(sv)
48214821
PERL_UNUSED_ARG(sv);
48224822
XSRETURN(1);
48234823

4824+
void
4825+
set_xs_rc_stack(cv, sv)
4826+
CV *cv;
4827+
SV *sv;
4828+
PPCODE:
4829+
/* set or undet the CVf_XS_RCSTACK flag on the CV */
4830+
assert(SvTYPE(cv) == SVt_PVCV);
4831+
if (SvTRUE(sv))
4832+
CvXS_RCSTACK_on(cv);
4833+
else
4834+
CvXS_RCSTACK_off(cv);
4835+
XSRETURN(0);
4836+
4837+
void
4838+
rc_add(sv1, sv2)
4839+
SV *sv1;
4840+
SV *sv2;
4841+
PPCODE:
4842+
/* Do the XS equivalent of pp_add(), while expecting a
4843+
* reference-counted stack */
4844+
4845+
/* manipulate the stack directly */
4846+
PERL_UNUSED_ARG(sv1);
4847+
PERL_UNUSED_ARG(sv2);
4848+
SV *r = newSViv(SvIV(PL_stack_sp[-1]) + SvIV(PL_stack_sp[0]));
4849+
rpp_replace_2_1(r);
4850+
return;
4851+
4852+
48244853

48254854
MODULE = XS::APItest PACKAGE = XS::APItest::AUTOLOADtest
48264855

ext/XS-APItest/t/rpp_invoke_xs.t

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#!perl
2+
#
3+
# Test the rpp_invoke_xs() function.
4+
# In particular, ensure that an XS CV flagged as CvXS_RCSTACK()
5+
# is called without being wrapped by xs_wrap() but works ok, with no
6+
# leaks or premature frees etc.
7+
8+
use warnings;
9+
use strict;
10+
use Test::More;
11+
use XS::APItest qw(set_xs_rc_stack rc_add);
12+
13+
14+
# Test that $_[0] has the expected refcount
15+
16+
sub rc_is {
17+
my (undef, $exp_rc, $desc) = @_;
18+
$exp_rc++ if (Internals::stack_refcounted() & 1);
19+
is(Internals::SvREFCNT($_[0]), $exp_rc, $desc);
20+
}
21+
22+
23+
# Mark the XS function as 'reference-counted-stack aware'.
24+
# There's no way do do this yet using XS syntax.
25+
26+
set_xs_rc_stack(\&rc_add, 1);
27+
28+
29+
# Basic sanity check
30+
31+
is (rc_add(7,15), 22, "7+15");
32+
33+
34+
# Args with RC==1 should be the same afterwards
35+
36+
{
37+
my ($x, $y) = (3, 16);
38+
rc_is($x, 1, '3+16 rc($x) before');
39+
rc_is($y, 1, '3+16 rc($y) before');
40+
is (rc_add($x, $y), 19, "3+16");
41+
rc_is($x, 1, '3+16 rc($x) after');
42+
rc_is($y, 1, '3+16 rc($y) after');
43+
}
44+
45+
46+
# Return value is a newSV kept alive just by the stack
47+
48+
rc_is(rc_add(34, 17), 1, "rc(34+17)");
49+
50+
51+
52+
done_testing();

inline.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -782,10 +782,11 @@ Perl_rpp_invoke_xs(pTHX_ CV *cv)
782782
PERL_ARGS_ASSERT_RPP_INVOKE_XS;
783783

784784
#ifdef PERL_RC_STACK
785-
Perl_xs_wrap(aTHX_ CvXSUB(cv), cv);
786-
#else
787-
CvXSUB(cv)(aTHX_ cv);
785+
if (!CvXS_RCSTACK(cv))
786+
Perl_xs_wrap(aTHX_ CvXSUB(cv), cv);
787+
else
788788
#endif
789+
CvXSUB(cv)(aTHX_ cv);
789790
}
790791

791792

0 commit comments

Comments
 (0)