PP(pp_stringify)
{
dVAR; dSP; dTARGET;
- sv_copypv(TARG,TOPs);
- SETTARG;
- RETURN;
+ SV * const sv = TOPs;
+ SETs(TARG);
+ sv_copypv(TARG, sv);
+ SvSETMAGIC(TARG);
+ /* no PUTBACK, SETs doesn't inc/dec SP */
+ return NORMAL;
}
PP(pp_gv)
PP(pp_and)
{
- dVAR; dSP;
+ dVAR;
PERL_ASYNC_CHECK();
- if (!SvTRUE(TOPs))
- RETURN;
- else {
- if (PL_op->op_type == OP_AND)
- --SP;
- RETURNOP(cLOGOP->op_other);
+ {
+ /* SP is not used to remove a variable that is saved across the
+ sv_2bool_flags call in SvTRUE_NN, if a RISC/CISC or low/high machine
+ register or load/store vs direct mem ops macro is introduced, this
+ should be a define block between direct PL_stack_sp and dSP operations,
+ presently, using PL_stack_sp is bias towards CISC cpus */
+ SV * const sv = *PL_stack_sp;
+ if (!SvTRUE_NN(sv))
+ return NORMAL;
+ else {
+ if (PL_op->op_type == OP_AND)
+ --PL_stack_sp;
+ return cLOGOP->op_other;
+ }
}
}
PP(pp_padsv)
{
- dVAR; dSP; dTARGET;
- XPUSHs(TARG);
- if (PL_op->op_flags & OPf_MOD) {
- if (PL_op->op_private & OPpLVAL_INTRO)
- if (!(PL_op->op_private & OPpPAD_STATE))
- SAVECLEARSV(PAD_SVl(PL_op->op_targ));
- if (PL_op->op_private & OPpDEREF) {
- PUTBACK;
- TOPs = vivify_ref(TOPs, PL_op->op_private & OPpDEREF);
- SPAGAIN;
+ dVAR; dSP;
+ EXTEND(SP, 1);
+ {
+ OP * const op = PL_op;
+ /* access PL_curpad once */
+ SV ** const padentry = &(PAD_SVl(op->op_targ));
+ {
+ dTARG;
+ TARG = *padentry;
+ PUSHs(TARG);
+ PUTBACK; /* no pop/push after this, TOPs ok */
+ }
+ if (op->op_flags & OPf_MOD) {
+ if (op->op_private & OPpLVAL_INTRO)
+ if (!(op->op_private & OPpPAD_STATE))
+ save_clearsv(padentry);
+ if (op->op_private & OPpDEREF) {
+ /* TOPs is equivalent to TARG here. Using TOPs (SP) rather
+ than TARG reduces the scope of TARG, so it does not
+ span the call to save_clearsv, resulting in smaller
+ machine code. */
+ TOPs = vivify_ref(TOPs, op->op_private & OPpDEREF);
+ }
}
+ return op->op_next;
}
- RETURN;
}
PP(pp_readline)
RX_MATCH_UTF8_set(rx, DO_UTF8(TARG));
+ /* We need to know this incase we fail out early - pos() must be reset */
+ global = dynpm->op_pmflags & PMf_GLOBAL;
+
/* PMdf_USED is set after a ?? matches once */
if (
#ifdef USE_ITHREADS
#endif
) {
DEBUG_r(PerlIO_printf(Perl_debug_log, "?? already matched once"));
- failure:
-
- if (gimme == G_ARRAY)
- RETURN;
- RETPUSHNO;
+ goto nope;
}
if (RX_MINLEN(rx) > (I32)len) {
DEBUG_r(PerlIO_printf(Perl_debug_log, "String shorter than min possible regex match\n"));
- goto failure;
+ goto nope;
}
truebase = t = s;
/* XXXX What part of this is needed with true \G-support? */
- if ((global = dynpm->op_pmflags & PMf_GLOBAL)) {
+ if (global) {
RX_OFFS(rx)[0].start = -1;
if (SvTYPE(TARG) >= SVt_PVMG && SvMAGIC(TARG)) {
MAGIC* const mg = mg_find(TARG, PERL_MAGIC_regex_global);
itersvp = CxITERVAR(cx);
switch (CxTYPE(cx)) {
- case CXt_LOOP_LAZYSV:
- {
- /* string increment */
- SV* cur = cx->blk_loop.state_u.lazysv.cur;
- SV *end = cx->blk_loop.state_u.lazysv.end;
- /* If the maximum is !SvOK(), pp_enteriter substitutes PL_sv_no.
- It has SvPVX of "" and SvCUR of 0, which is what we want. */
- STRLEN maxlen = 0;
- const char *max = SvPV_const(end, maxlen);
- if (SvNIOK(cur) || SvCUR(cur) > maxlen)
- RETPUSHNO;
- if (SvREFCNT(*itersvp) == 1 && !SvMAGICAL(*itersvp)) {
- /* safe to reuse old SV */
- sv_setsv(*itersvp, cur);
- }
- else
- {
- /* we need a fresh SV every time so that loop body sees a
- * completely new SV for closures/references to work as
- * they used to */
- oldsv = *itersvp;
- *itersvp = newSVsv(cur);
- SvREFCNT_dec(oldsv);
- }
- if (strEQ(SvPVX_const(cur), max))
- sv_setiv(cur, 0); /* terminate next time */
- else
- sv_inc(cur);
- break;
+ case CXt_LOOP_LAZYSV: /* string increment */
+ {
+ SV* cur = cx->blk_loop.state_u.lazysv.cur;
+ SV *end = cx->blk_loop.state_u.lazysv.end;
+ /* If the maximum is !SvOK(), pp_enteriter substitutes PL_sv_no.
+ It has SvPVX of "" and SvCUR of 0, which is what we want. */
+ STRLEN maxlen = 0;
+ const char *max = SvPV_const(end, maxlen);
+ if (SvNIOK(cur) || SvCUR(cur) > maxlen)
+ RETPUSHNO;
+
+ oldsv = *itersvp;
+ if (SvREFCNT(oldsv) == 1 && !SvMAGICAL(oldsv)) {
+ /* safe to reuse old SV */
+ sv_setsv(oldsv, cur);
}
+ else
+ {
+ /* we need a fresh SV every time so that loop body sees a
+ * completely new SV for closures/references to work as
+ * they used to */
+ *itersvp = newSVsv(cur);
+ SvREFCNT_dec(oldsv);
+ }
+ if (strEQ(SvPVX_const(cur), max))
+ sv_setiv(cur, 0); /* terminate next time */
+ else
+ sv_inc(cur);
+ break;
+ }
- case CXt_LOOP_LAZYIV:
- /* integer increment */
- if (cx->blk_loop.state_u.lazyiv.cur > cx->blk_loop.state_u.lazyiv.end)
+ case CXt_LOOP_LAZYIV: /* integer increment */
+ {
+ IV cur = cx->blk_loop.state_u.lazyiv.cur;
+ if (cur > cx->blk_loop.state_u.lazyiv.end)
RETPUSHNO;
+ oldsv = *itersvp;
/* don't risk potential race */
- if (SvREFCNT(*itersvp) == 1 && !SvMAGICAL(*itersvp)) {
+ if (SvREFCNT(oldsv) == 1 && !SvMAGICAL(oldsv)) {
/* safe to reuse old SV */
- sv_setiv(*itersvp, cx->blk_loop.state_u.lazyiv.cur);
+ sv_setiv(oldsv, cur);
}
else
{
/* we need a fresh SV every time so that loop body sees a
* completely new SV for closures/references to work as they
* used to */
- oldsv = *itersvp;
- *itersvp = newSViv(cx->blk_loop.state_u.lazyiv.cur);
+ *itersvp = newSViv(cur);
SvREFCNT_dec(oldsv);
}
- if (cx->blk_loop.state_u.lazyiv.cur == IV_MAX) {
+ if (cur == IV_MAX) {
/* Handle end of range at IV_MAX */
cx->blk_loop.state_u.lazyiv.end = IV_MIN;
} else
++cx->blk_loop.state_u.lazyiv.cur;
break;
+ }
- case CXt_LOOP_FOR:
+ case CXt_LOOP_FOR: /* iterate array */
{
- /* iterate array */
AV *av = cx->blk_loop.state_u.ary.ary;
SV *sv;
bool av_is_stack = FALSE;
+ IV ix;
if (!av) {
av_is_stack = TRUE;
av = PL_curstack;
}
if (PL_op->op_private & OPpITER_REVERSED) {
- if (cx->blk_loop.state_u.ary.ix <= (av_is_stack
- ? cx->blk_loop.resetsp + 1 : 0))
+ ix = --cx->blk_loop.state_u.ary.ix;
+ if (ix <= (av_is_stack ? cx->blk_loop.resetsp : -1))
RETPUSHNO;
-
- if (SvMAGICAL(av) || AvREIFY(av)) {
- SV * const * const svp = av_fetch(av, --cx->blk_loop.state_u.ary.ix, FALSE);
- sv = svp ? *svp : NULL;
- }
- else {
- sv = AvARRAY(av)[--cx->blk_loop.state_u.ary.ix];
- }
}
else {
- if (cx->blk_loop.state_u.ary.ix >= (av_is_stack ? cx->blk_oldsp :
- AvFILL(av)))
+ ix = ++cx->blk_loop.state_u.ary.ix;
+ if (ix > (av_is_stack ? cx->blk_oldsp : AvFILL(av)))
RETPUSHNO;
-
- if (SvMAGICAL(av) || AvREIFY(av)) {
- SV * const * const svp = av_fetch(av, ++cx->blk_loop.state_u.ary.ix, FALSE);
- sv = svp ? *svp : NULL;
- }
- else {
- sv = AvARRAY(av)[++cx->blk_loop.state_u.ary.ix];
- }
}
- if (sv && SvIS_FREED(sv)) {
- *itersvp = NULL;
- Perl_croak(aTHX_ "Use of freed value in iteration");
+ if (SvMAGICAL(av) || AvREIFY(av)) {
+ SV * const * const svp = av_fetch(av, ix, FALSE);
+ sv = svp ? *svp : NULL;
+ }
+ else {
+ sv = AvARRAY(av)[ix];
}
if (sv) {
+ if (SvIS_FREED(sv)) {
+ *itersvp = NULL;
+ Perl_croak(aTHX_ "Use of freed value in iteration");
+ }
SvTEMP_off(sv);
SvREFCNT_inc_simple_void_NN(sv);
}
else
sv = &PL_sv_undef;
+
if (!av_is_stack && sv == &PL_sv_undef) {
SV *lv = newSV_type(SVt_PVLV);
LvTYPE(lv) = 'y';
sv_magic(lv, NULL, PERL_MAGIC_defelem, NULL, 0);
LvTARG(lv) = SvREFCNT_inc_simple(av);
- LvTARGOFF(lv) = cx->blk_loop.state_u.ary.ix;
+ LvTARGOFF(lv) = ix;
LvTARGLEN(lv) = (STRLEN)UV_MAX;
sv = lv;
}
default:
DIE(aTHX_ "panic: pp_iter, type=%u", CxTYPE(cx));
}
- RETPUSHYES;
+ RETPUSHYES;
}
/*