7474# define THR_newSVsv_cow (sv ) newSVsv_flags((sv), SV_GMAGIC|SV_NOSTEAL)
7575#endif
7676
77+ /* PL_op->op_private & OPpENTERSUB_HASTARG feature was added in
78+
79+ d30110745a - Ilya Zakharevich -8/26/1999 11:33:01 PM - 5.5.61
80+ Speeding up XSUB calls up to 66%
81+ Addendum: it's "only" 33% speedup.
82+
83+ These 3 are highly optimized version of 3 macros from pp.h that were
84+ purpose made mostly for EU::PXS's private use, but we DO NOT want to execute
85+ a slower sv_newmortal() + sv_set_i_u_n_v_mg(), instead of
86+ sv_2mortal(newSV_i_u_n_v()).
87+
88+ These macros do not put the new SV* on the stack. Caller is responsible for
89+ that.
90+
91+ Arg _nsv is an uninitialized SV* variable, a new SV* will be placed in
92+ the _nsv var. SvREFCNT()/SV* lifecycle details are handled by the macro.
93+ The caller IS NOT allowed to execute a "sv_2mortal(_nsv);" on the new SV*.
94+
95+ sv_set_i_u_n_v_mg() is required to a huge amount of safety checks like
96+ de-COW PVs RVs, COWs, sv_upgrade(), copy old SV body contents to a higher
97+ order SV body, etc.
98+
99+ Also if G_LIST context, we do not want Perl_leave_adjust_stacks() to create
100+ a mortal copy of our PAD SV* TARG. Example of returning a dXSTARG, and
101+ Perl_leave_adjust_stacks() instantly makes a mortal dup of it is this code
102+ $self->logtime(time());
103+ */
104+
105+
106+
107+ /* set TARG to the IV value i. If do_taint is false,
108+ * assume that PL_tainted can never be true */
109+ #define TMR_TARGi (_nsv , i , do_taint ) \
110+ STMT_START { \
111+ IV TARGi_iv = i; \
112+ if (GIMME_V == G_LIST || !(PL_op->op_private & OPpENTERSUB_HASTARG)) \
113+ _nsv = sv_2mortal(newSViv(TARGi_iv)); \
114+ else { \
115+ _nsv = PAD_SV(PL_op->op_targ); \
116+ if (LIKELY( \
117+ ((SvFLAGS(_nsv) & (SVTYPEMASK|SVf_THINKFIRST|SVf_IVisUV)) == SVt_IV) \
118+ & (do_taint ? !TAINT_get : 1))) \
119+ { \
120+ /* Cheap SvIOK_only(). \
121+ * Assert that flags which SvIOK_only() would test or \
122+ * clear can't be set, because we're SVt_IV */ \
123+ assert (!(SvFLAGS (_nsv ) & \
124+ (SVf_OOK |SVf_UTF8 |(SVf_OK & ~(SVf_IOK |SVp_IOK ))))); \
125+ SvFLAGS (_nsv ) |= (SVf_IOK |SVp_IOK ); \
126+ /* SvIV_set() where sv_any points to head */ \
127+ _nsv -> sv_u .svu_iv = TARGi_iv ; \
128+ } \
129+ else \
130+ sv_setiv_mg (_nsv , TARGi_iv ); \
131+ } \
132+ } STMT_END
133+
134+ /* set TARG to the UV value u. If do_taint is false,
135+ * assume that PL_tainted can never be true */
136+ #define TMR_TARGu (_nsv , u , do_taint ) \
137+ STMT_START { \
138+ UV TARGu_uv = u ; \
139+ if (GIMME_V == G_LIST || !(PL_op -> op_private & OPpENTERSUB_HASTARG )) \
140+ _nsv = sv_2mortal (newSVuv (TARGu_uv )); \
141+ else { \
142+ _nsv = PAD_SV (PL_op -> op_targ ); \
143+ if (LIKELY ( \
144+ ((SvFLAGS (_nsv ) & (SVTYPEMASK |SVf_THINKFIRST |SVf_IVisUV )) == SVt_IV ) \
145+ & (do_taint ? !TAINT_get : 1 ) \
146+ & (TARGu_uv <= (UV )IV_MAX ))) \
147+ { \
148+ /* Cheap SvIOK_only(). \
149+ * Assert that flags which SvIOK_only() would test or \
150+ * clear can't be set, because we're SVt_IV */ \
151+ assert (!(SvFLAGS (_nsv ) & \
152+ (SVf_OOK |SVf_UTF8 |(SVf_OK & ~(SVf_IOK |SVp_IOK ))))); \
153+ SvFLAGS (_nsv ) |= (SVf_IOK |SVp_IOK ); \
154+ /* SvIV_set() where sv_any points to head */ \
155+ _nsv -> sv_u .svu_iv = TARGu_uv ; \
156+ } \
157+ else \
158+ sv_setuv_mg (_nsv , TARGu_uv ); \
159+ } \
160+ } STMT_END
161+
162+ /* set TARG to the NV value n. If do_taint is false,
163+ * assume that PL_tainted can never be true */
164+ #define TMR_TARGn (_nsv , n , do_taint ) \
165+ STMT_START { \
166+ NV TARGn_nv = n ; \
167+ if (GIMME_V == G_LIST || !(PL_op -> op_private & OPpENTERSUB_HASTARG )) \
168+ _nsv = sv_2mortal (newSVnv (TARGn_nv )); \
169+ else { \
170+ _nsv = PAD_SV (PL_op -> op_targ ); \
171+ if (LIKELY ( \
172+ ((SvFLAGS (_nsv ) & (SVTYPEMASK |SVf_THINKFIRST )) == SVt_NV ) \
173+ & (do_taint ? !TAINT_get : 1 ))) \
174+ { \
175+ /* Cheap SvNOK_only(). \
176+ * Assert that flags which SvNOK_only() would test or \
177+ * clear can't be set, because we're SVt_NV */ \
178+ assert (!(SvFLAGS (_nsv ) & \
179+ (SVf_OOK |SVf_UTF8 |(SVf_OK & ~(SVf_NOK |SVp_NOK ))))); \
180+ SvFLAGS (_nsv ) |= (SVf_NOK |SVp_NOK ); \
181+ SvNV_set (_nsv , TARGn_nv ); \
182+ } \
183+ else \
184+ sv_setnv_mg (_nsv , TARGn_nv ); \
185+ } \
186+ } STMT_END
187+
77188#define IV_1E6 1000000
78189#define IV_1E7 10000000
79190#define IV_1E9 1000000000
@@ -1143,11 +1254,13 @@ INCLUDE: const-xs.inc
11431254
11441255#if defined(HAS_USLEEP ) && defined(HAS_GETTIMEOFDAY )
11451256
1146- NV
1257+ void
11471258usleep (useconds )
11481259 NV useconds
11491260 PREINIT :
11501261 struct timeval Ta , Tb ;
1262+ SV * rsv ;
1263+ NV RETVAL ;
11511264 CODE :
11521265 gettimeofday (& Ta , NULL );
11531266 if (items > 0 ) {
@@ -1173,17 +1286,19 @@ usleep(useconds)
11731286 printf ("[%ld %ld] [%ld %ld]\n" , Tb .tv_sec , Tb .tv_usec , Ta .tv_sec , Ta .tv_usec );
11741287# endif
11751288 RETVAL = NV_1E6 * (Tb .tv_sec - Ta .tv_sec )+ (NV )((IV )Tb .tv_usec - (IV )Ta .tv_usec );
1176-
1177- OUTPUT :
1178- RETVAL
1289+ TMR_TARGn ( rsv , RETVAL , 1 );
1290+ SETs ( rsv );
1291+ return ; /* no PUTBACK no PUSH, 1 in, 1 out */
11791292
11801293# if defined(TIME_HIRES_NANOSLEEP )
11811294
1182- NV
1295+ void
11831296nanosleep (nsec )
11841297 NV nsec
11851298 PREINIT :
11861299 struct timespec sleepfor , unslept ;
1300+ SV * rsv ;
1301+ NV RETVAL ;
11871302 CODE :
11881303 if (nsec < 0.0 )
11891304 croak ("%s(%" NVgf "%s" , "Time::HiRes::nanosleep" , nsec ,
@@ -1194,8 +1309,9 @@ nanosleep(nsec)
11941309 } else {
11951310 RETVAL = nsec_without_unslept (& sleepfor , & unslept );
11961311 }
1197- OUTPUT :
1198- RETVAL
1312+ TMR_TARGn (rsv , RETVAL , 1 );
1313+ SETs (rsv );
1314+ return ; /* no PUTBACK no PUSH, 1 in, 1 out */
11991315
12001316# else /* #if defined(TIME_HIRES_NANOSLEEP) */
12011317
@@ -1211,11 +1327,13 @@ nanosleep(nsec)
12111327
12121328# endif /* #if defined(TIME_HIRES_NANOSLEEP) */
12131329
1214- NV
1330+ void
12151331sleep (...)
12161332 PREINIT :
12171333 struct timeval Ta , Tb ;
1218- CODE :
1334+ SV * rsv ;
1335+ NV RETVAL ;
1336+ PPCODE :
12191337 gettimeofday (& Ta , NULL );
12201338 if (items > 0 ) {
12211339 NV seconds = SvNV (ST (0 ));
@@ -1250,9 +1368,10 @@ sleep(...)
12501368 printf ("[%ld %ld] [%ld %ld]\n" , Tb .tv_sec , Tb .tv_usec , Ta .tv_sec , Ta .tv_usec );
12511369# endif
12521370 RETVAL = (NV )(Tb .tv_sec - Ta .tv_sec )+ 0.000001 * (NV )(Tb .tv_usec - Ta .tv_usec );
1253-
1254- OUTPUT :
1255- RETVAL
1371+ TMR_TARGn (rsv , RETVAL , 1 );
1372+ PUSHs (rsv );
1373+ PUTBACK ;
1374+ return ;
12561375
12571376#else /* #if defined(HAS_USLEEP) && defined(HAS_GETTIMEOFDAY) */
12581377
@@ -1270,11 +1389,14 @@ usleep(useconds)
12701389
12711390#ifdef HAS_UALARM
12721391
1273- IV
1392+ void
12741393ualarm (useconds ,uinterval = 0 )
12751394 int useconds
12761395 int uinterval
1277- CODE :
1396+ PREINIT :
1397+ SV * rsv ;
1398+ IV RETVAL ;
1399+ PPCODE :
12781400 if (useconds < 0 || uinterval < 0 )
12791401 croak ("%s(%d, %d%s" ,
12801402 "Time::HiRes::ualarm" , useconds , uinterval ,
@@ -1298,15 +1420,19 @@ ualarm(useconds,uinterval=0)
12981420
12991421 RETVAL = ualarm (useconds , uinterval );
13001422# endif
1423+ TMR_TARGi (rsv , RETVAL , 1 );
1424+ PUSHs (rsv );
1425+ PUTBACK ;
1426+ return ;
13011427
1302- OUTPUT :
1303- RETVAL
1304-
1305- NV
1428+ void
13061429alarm (seconds ,interval = 0 )
13071430 NV seconds
13081431 NV interval
1309- CODE :
1432+ PREINIT :
1433+ SV * rsv ;
1434+ NV RETVAL ;
1435+ PPCODE :
13101436 if (seconds < 0.0 || interval < 0.0 )
13111437 croak ("%s (%" NVgf ", %" NVgf "%s ",
13121438 "Time ::HiRes ::alarm ", seconds , interval ,
@@ -1348,9 +1474,10 @@ alarm(seconds,interval=0)
13481474 RETVAL = (NV )ualarm ( useconds , uinterval ) / NV_1E6 ;
13491475# endif
13501476 }
1351-
1352- OUTPUT :
1353- RETVAL
1477+ TMR_TARGn (rsv , RETVAL , 1 );
1478+ PUSHs (rsv );
1479+ PUTBACK ;
1480+ return ;
13541481
13551482#else /* #ifdef HAS_UALARM */
13561483
@@ -1387,6 +1514,7 @@ gettimeofday()
13871514 PREINIT :
13881515 struct timeval Tp ;
13891516 int status ;
1517+ OP * const op = PL_op ;
13901518 U8 is_G_LIST = GIMME_V == G_LIST ;
13911519 PPCODE :
13921520 if (is_G_LIST )
@@ -1399,15 +1527,41 @@ gettimeofday()
13991527 PUSHs (sv_2mortal (newSViv (sec )));
14001528 PUSHs (sv_2mortal (newSViv (usec )));
14011529 } else {
1530+ /* no Perl_leave_adjust_stacks() hazard here,
1531+ only a PP vs call_sv() hazard */
14021532 NV nv = Tp .tv_sec + (Tp .tv_usec / NV_1E6 );
1403- PUSHs (sv_2mortal (newSVnv (nv )));
1533+ const U8 do_taint = 1 ;
1534+ NV TARGn_nv = nv ;
1535+ SV * rsv ;
1536+ if (op -> op_private & OPpENTERSUB_HASTARG ) {
1537+ rsv = PAD_SV (op -> op_targ );
1538+ if (LIKELY (
1539+ ((SvFLAGS (rsv ) & (SVTYPEMASK |SVf_THINKFIRST )) == SVt_NV )
1540+ & (do_taint ? !TAINT_get : 1 )))
1541+ {
1542+ /* Cheap SvNOK_only().
1543+ * Assert that flags which SvNOK_only() would test or
1544+ * clear can't be set, because we're SVt_NV */
1545+ assert (!(SvFLAGS (rsv ) &
1546+ (SVf_OOK |SVf_UTF8 |(SVf_OK & ~(SVf_NOK |SVp_NOK )))));
1547+ SvFLAGS (rsv ) |= (SVf_NOK |SVp_NOK );
1548+ SvNV_set (rsv , TARGn_nv );
1549+ }
1550+ else
1551+ sv_setnv_mg (rsv , TARGn_nv );
1552+ }
1553+ else
1554+ rsv = sv_2mortal (newSVnv (TARGn_nv ));
1555+ PUSHs (rsv );
14041556 }
14051557 }
14061558
1407- NV
1559+ void
14081560time ()
14091561 PREINIT :
14101562 struct timeval Tp ;
1563+ SV * rsv ;
1564+ NV RETVAL ;
14111565 CODE :
14121566 int status ;
14131567 status = gettimeofday (& Tp , NULL );
@@ -1416,8 +1570,10 @@ time()
14161570 } else {
14171571 RETVAL = -1.0 ;
14181572 }
1419- OUTPUT :
1420- RETVAL
1573+ TMR_TARGn (rsv , RETVAL , 1 );
1574+ PUSHs (rsv ); /* 0 in, 1 out, entersub guarenteed 1 slot */
1575+ PUTBACK ;
1576+ return ;
14211577
14221578#endif /* #ifdef HAS_GETTIMEOFDAY */
14231579
@@ -1579,22 +1735,25 @@ utime(accessed, modified, ...)
15791735
15801736#if defined(TIME_HIRES_CLOCK_GETTIME )
15811737
1582- NV
1738+ void
15831739clock_gettime (clock_id = CLOCK_REALTIME )
15841740 clockid_t clock_id
15851741 PREINIT :
15861742 struct timespec ts ;
15871743 int status ;
1588- CODE :
1744+ SV * rsv ;
1745+ NV RETVAL ;
1746+ PPCODE :
15891747# ifdef TIME_HIRES_CLOCK_GETTIME_SYSCALL
15901748 status = syscall (SYS_clock_gettime , clock_id , & ts );
15911749# else
15921750 status = clock_gettime (clock_id , & ts );
15931751# endif
15941752 RETVAL = status == 0 ? ts .tv_sec + (NV ) ts .tv_nsec / NV_1E9 : -1 ;
1595-
1596- OUTPUT :
1597- RETVAL
1753+ TMR_TARGn (rsv , RETVAL , 1 );
1754+ PUSHs (rsv ); /* 0 or 1 in, 1 out, PPCODE: did rewind */
1755+ PUTBACK ;
1756+ return ;
15981757
15991758#else /* if defined(TIME_HIRES_CLOCK_GETTIME) */
16001759
0 commit comments