Skip to content

Commit ba5e04c

Browse files
committed
Time::HiRes::stat() cleanup and optimize fake OP struct construction
-XPUSHs() requires saving the SV* retval of sv_2mortal(newSVsv()) around a possible Perl_stack_grow(), split the EXTEND from the PUSH, so SV* is held only in volatile registers (liveness). -over EXTEND to 13 elements instead of 1 element. Why not? pp_stat()/pp_lstat() have to do the Perl_stack_grow() call if we don't do it. -remove Zero() macro and use a function call free struct initializer. Just b/c GCC and its offshoot Clang will inline a fixed length memset() doesn't make it part of ISO C. MSVC compiler never inlines memset() calls on WinPerl (b/c P5P never added the magic sauce to ask for that feature). More portably, P5P has never verified the machine code output of all known commercial Unix CCs on all CPU archs regarding inlining memset(). -when filling out the fake OP, do some instruction level parallelism like filling in fakeop with 0s, while digging through my_perl->Iop->op_flags, my_perl->Icurstackinfo->si_cxsubix, my_perl->Icurstackinfo->si_cxstack, and etc, as part of GIMME_V macro, which used to be a libperl.so exported function call a very long time ago IIRC. Another example, translate ix?OP_LSTAT:OP_STAT while translating gm==G_LIST?OPf_WANT_LIST:gm==G_SCALAR?OPf_WANT_SCALAR:OPf_WANT_VOID. Dig through PLT/GOT/PE sym table as part of PL_ppaddr[op_type] while writing to C stk mem as part of fakeop.op_type = op_type -change fakeop.op_ppaddr(aTHX); to ppaddr(aTHX); b/c some CCs have a low IQ and can't prove statement "PL_op = &fakeop;" won't modify field fakeop.op_ppaddr in our C auto storage OP struct var. -don't execute the Perl_sv_2uv_flags() getter method pointlessly inside UV atime = SvUV(ST( 8)); if static function hrstatns() is a NOOP and is inlined and totally optimized away since in some build configs, hrstatns() only does atime_nsec = 0; mtime_nsec = 0; ctime_nsec = 0; Windows is an example. -change SvUV(ST( 8)); to SvUV(SPBASE[ 8]); don't deref my_perl->Istack_base over and over
1 parent 565b8ff commit ba5e04c

File tree

1 file changed

+38
-21
lines changed

1 file changed

+38
-21
lines changed

dist/Time-HiRes/HiRes.xs

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1515,39 +1515,56 @@ void
15151515
stat(...)
15161516
PROTOTYPE: ;$
15171517
PREINIT:
1518-
OP fakeop;
1519-
int nret;
1518+
SSize_t nret;
1519+
SV* sv_arg;
1520+
SV** SPBASE;
15201521
ALIAS:
15211522
Time::HiRes::lstat = 1
15221523
PPCODE:
1523-
XPUSHs(sv_2mortal(newSVsv(items == 1 ? ST(0) : DEFSV)));
1524+
sv_arg = items == 1 ? ST(0) : DEFSV;
1525+
EXTEND(SP, 13);
1526+
/* XXX will pp_stat()/pp_lstat() really modify $_[0] ? */
1527+
PUSHs(sv_2mortal(newSVsv(sv_arg)));
15241528
PUTBACK;
15251529
ENTER;
15261530
PL_laststatval = -1;
15271531
SAVEOP();
1528-
Zero(&fakeop, 1, OP);
1529-
fakeop.op_type = ix ? OP_LSTAT : OP_STAT;
1530-
fakeop.op_ppaddr = PL_ppaddr[fakeop.op_type];
1531-
fakeop.op_flags = GIMME_V == G_LIST ? OPf_WANT_LIST :
1532-
GIMME_V == G_SCALAR ? OPf_WANT_SCALAR : OPf_WANT_VOID;
1533-
PL_op = &fakeop;
1534-
(void)fakeop.op_ppaddr(aTHX);
1535-
SPAGAIN;
1532+
{
1533+
OP* (*ppaddr)(pTHX);
1534+
U8 gimme = GIMME_V; /* ILP */
1535+
/* extern "C" memset() doesn't know struct OP's alignment. ISO C doesn't
1536+
promise Zero(); and memset(); will inline. But this does. Now the CC can
1537+
detangle for us, what OP fields will get a 0/NULL, or our values. */
1538+
OP fakeop = {0};
1539+
U16 op_type = ix ? OP_LSTAT : OP_STAT;
1540+
fakeop.op_flags = gimme == G_LIST ? OPf_WANT_LIST :
1541+
gimme == G_SCALAR ? OPf_WANT_SCALAR : OPf_WANT_VOID; /* ILP */
1542+
ppaddr = PL_ppaddr[op_type];
1543+
fakeop.op_type = op_type;
1544+
fakeop.op_ppaddr = ppaddr; /* ILP */
1545+
PL_op = &fakeop;
1546+
(void)ppaddr(aTHX);
1547+
}
15361548
LEAVE;
1537-
nret = SP+1 - &ST(0);
1549+
SPAGAIN;
1550+
SPBASE = &ST(0);
1551+
nret = SP+1 - SPBASE;
15381552
if (nret == 13) {
1539-
UV atime = SvUV(ST( 8));
1540-
UV mtime = SvUV(ST( 9));
1541-
UV ctime = SvUV(ST(10));
15421553
UV atime_nsec;
15431554
UV mtime_nsec;
15441555
UV ctime_nsec;
15451556
hrstatns(&atime_nsec, &mtime_nsec, &ctime_nsec);
1546-
if (atime_nsec)
1547-
ST( 8) = sv_2mortal(newSVnv(atime + (NV) atime_nsec / NV_1E9));
1548-
if (mtime_nsec)
1549-
ST( 9) = sv_2mortal(newSVnv(mtime + (NV) mtime_nsec / NV_1E9));
1550-
if (ctime_nsec)
1551-
ST(10) = sv_2mortal(newSVnv(ctime + (NV) ctime_nsec / NV_1E9));
1557+
if (atime_nsec) { /* on certain configs hrstatns() is a NOOP */
1558+
UV atime = SvUV(SPBASE[ 8]);
1559+
SPBASE[ 8] = sv_2mortal(newSVnv(atime + (NV) atime_nsec / NV_1E9));
1560+
}
1561+
if (mtime_nsec) {
1562+
UV mtime = SvUV(SPBASE[ 9]);
1563+
SPBASE[ 9] = sv_2mortal(newSVnv(mtime + (NV) mtime_nsec / NV_1E9));
1564+
}
1565+
if (ctime_nsec) {
1566+
UV ctime = SvUV(SPBASE[10]);
1567+
SPBASE[10] = sv_2mortal(newSVnv(ctime + (NV) ctime_nsec / NV_1E9));
1568+
}
15521569
}
15531570
XSRETURN(nret);

0 commit comments

Comments
 (0)