summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2014-02-27 16:32:34 +0000
committerDavid Mitchell <davem@iabyn.com>2014-02-27 16:32:34 +0000
commite958ef3d8fccb2d78757ebb06ce8b1030ef4f1d0 (patch)
treee1e560a9e7820e720fd99ef8f3d3c8ba46880dc6
parent72b09e4f13cced68883e83d20365f3a68de1740c (diff)
parent60779a30f61297ad86e175f686b7bc697c7b8e51 (diff)
downloadperl-e958ef3d8fccb2d78757ebb06ce8b1030ef4f1d0.tar.gz
[MERGE] optmise pp_entersub code
Do various bits of minor fiddling with the code of Perl_pp_entersub to make the binary smaller and hopefully faster. All the usual stuff: sprinkling LIKELY(), altering scope of vars etc. All of this should make no functional difference, expect conceivably the "SvPADTMP() not on IS_PADGV()" change (which also affects code outside pp_entersub()). This series of commits reduces the size of the pp_entersub object on gcc x86_64 by about 11%, and shows no measurable change in performance (i.e. noise dominates).
-rw-r--r--intrpvar.h2
-rw-r--r--op.c1
-rw-r--r--pp.c15
-rw-r--r--pp_ctl.c8
-rw-r--r--pp_hot.c195
-rw-r--r--pp_sort.c4
-rw-r--r--regexec.c3
7 files changed, 128 insertions, 100 deletions
diff --git a/intrpvar.h b/intrpvar.h
index 3472215eb1..2c1b73ee49 100644
--- a/intrpvar.h
+++ b/intrpvar.h
@@ -76,6 +76,7 @@ PERLVAR(I, tainted, bool) /* using variables controlled by $< */
PERLVAR(I, delaymagic, U16) /* ($<,$>) = ... */
PERLVAR(I, localizing, U8) /* are we processing a local() list? */
PERLVAR(I, in_eval, U8) /* trap "fatal" errors? */
+PERLVAR(I, defgv, GV *) /* the *_ glob */
/*
=for apidoc mn|bool|PL_dowarn
@@ -349,7 +350,6 @@ PERLVAR(I, psig_pend, int *) /* per-signal "count" of pending */
/* shortcuts to various I/O objects */
PERLVAR(I, stdingv, GV *) /* *STDIN */
PERLVAR(I, stderrgv, GV *) /* *STDERR */
-PERLVAR(I, defgv, GV *)
PERLVAR(I, argvgv, GV *) /* *ARGV */
PERLVAR(I, argvoutgv, GV *) /* *ARGVOUT */
PERLVAR(I, argvout_stack, AV *)
diff --git a/op.c b/op.c
index 45a8a37ac9..85158006b7 100644
--- a/op.c
+++ b/op.c
@@ -5192,7 +5192,6 @@ Perl_newPADOP(pTHX_ I32 type, I32 flags, SV *sv)
SvREFCNT_dec(PAD_SVl(padop->op_padix));
PAD_SETSV(padop->op_padix, sv);
assert(sv);
- SvPADTMP_on(sv);
padop->op_next = (OP*)padop;
padop->op_flags = (U8)flags;
if (PL_opargs[type] & OA_RETSCALAR)
diff --git a/pp.c b/pp.c
index 1674ae6011..4ec6887dfd 100644
--- a/pp.c
+++ b/pp.c
@@ -571,8 +571,10 @@ S_refto(pTHX_ SV *sv)
SvTEMP_off(sv);
SvREFCNT_inc_void_NN(sv);
}
- else if (SvPADTMP(sv) && !IS_PADGV(sv))
+ else if (SvPADTMP(sv)) {
+ assert(!IS_PADGV(sv));
sv = newSVsv(sv);
+ }
else {
SvTEMP_off(sv);
SvREFCNT_inc_void_NN(sv);
@@ -1707,10 +1709,11 @@ PP(pp_repeat)
SvREADONLY_on(*SP);
}
#else
- if (*SP)
- {
- if (mod && SvPADTMP(*SP) && !IS_PADGV(*SP))
+ if (*SP) {
+ if (mod && SvPADTMP(*SP)) {
+ assert(!IS_PADGV(*SP));
*SP = sv_mortalcopy(*SP);
+ }
SvTEMP_off((*SP));
}
#endif
@@ -4896,8 +4899,10 @@ PP(pp_lslice)
is_something_there = TRUE;
if (!(*lelem = firstrelem[ix]))
*lelem = &PL_sv_undef;
- else if (mod && SvPADTMP(*lelem) && !IS_PADGV(*lelem))
+ else if (mod && SvPADTMP(*lelem)) {
+ assert(!IS_PADGV(*lelem));
*lelem = firstrelem[ix] = sv_mortalcopy(*lelem);
+ }
}
}
if (is_something_there)
diff --git a/pp_ctl.c b/pp_ctl.c
index 43466fe56c..7b516da59e 100644
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -938,7 +938,8 @@ PP(pp_grepstart)
SAVEVPTR(PL_curpm);
src = PL_stack_base[*PL_markstack_ptr];
- if (SvPADTMP(src) && !IS_PADGV(src)) {
+ if (SvPADTMP(src)) {
+ assert(!IS_PADGV(src));
src = PL_stack_base[*PL_markstack_ptr] = sv_mortalcopy(src);
PL_tmps_floor++;
}
@@ -1090,7 +1091,10 @@ PP(pp_mapwhile)
/* set $_ to the new source item */
src = PL_stack_base[PL_markstack_ptr[-1]];
- if (SvPADTMP(src) && !IS_PADGV(src)) src = sv_mortalcopy(src);
+ if (SvPADTMP(src)) {
+ assert(!IS_PADGV(src));
+ src = sv_mortalcopy(src);
+ }
SvTEMP_off(src);
if (PL_op->op_private & OPpGREP_LEX)
PAD_SVl(PL_op->op_targ) = src;
diff --git a/pp_hot.c b/pp_hot.c
index d0b84a1622..ae88d83f48 100644
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -1916,8 +1916,10 @@ PP(pp_iter)
*itersvp = NULL;
Perl_croak(aTHX_ "Use of freed value in iteration");
}
- if (SvPADTMP(sv) && !IS_PADGV(sv))
+ if (SvPADTMP(sv)) {
+ assert(!IS_PADGV(sv));
sv = newSVsv(sv);
+ }
else {
SvTEMP_off(sv);
SvREFCNT_inc_simple_void_NN(sv);
@@ -2432,7 +2434,8 @@ PP(pp_grepwhile)
SAVEVPTR(PL_curpm);
src = PL_stack_base[*PL_markstack_ptr];
- if (SvPADTMP(src) && !IS_PADGV(src)) {
+ if (SvPADTMP(src)) {
+ assert(!IS_PADGV(src));
src = PL_stack_base[*PL_markstack_ptr] = sv_mortalcopy(src);
PL_tmps_floor++;
}
@@ -2522,70 +2525,72 @@ PP(pp_entersub)
I32 gimme;
const bool hasargs = (PL_op->op_flags & OPf_STACKED) != 0;
- if (!sv)
- DIE(aTHX_ "Not a CODE reference");
- switch (SvTYPE(sv)) {
- /* This is overwhelming the most common case: */
- case SVt_PVGV:
- we_have_a_glob:
- if (!(cv = GvCVu((const GV *)sv))) {
- HV *stash;
- cv = sv_2cv(sv, &stash, &gv, 0);
- }
- if (!cv) {
- ENTER;
- SAVETMPS;
- goto try_autoload;
- }
- break;
- case SVt_PVLV:
- if(isGV_with_GP(sv)) goto we_have_a_glob;
- /*FALLTHROUGH*/
- default:
- if (sv == &PL_sv_yes) { /* unfound import, ignore */
- if (hasargs)
- SP = PL_stack_base + POPMARK;
- else
- (void)POPMARK;
- RETURN;
- }
- SvGETMAGIC(sv);
- if (SvROK(sv)) {
- if (SvAMAGIC(sv)) {
- sv = amagic_deref_call(sv, to_cv_amg);
- /* Don't SPAGAIN here. */
- }
- }
- else {
- const char *sym;
- STRLEN len;
- if (!SvOK(sv))
- DIE(aTHX_ PL_no_usym, "a subroutine");
- sym = SvPV_nomg_const(sv, len);
- if (PL_op->op_private & HINT_STRICT_REFS)
- DIE(aTHX_ "Can't use string (\"%" SVf32 "\"%s) as a subroutine ref while \"strict refs\" in use", sv, len>32 ? "..." : "");
- cv = get_cvn_flags(sym, len, GV_ADD|SvUTF8(sv));
- break;
- }
- cv = MUTABLE_CV(SvRV(sv));
- if (SvTYPE(cv) == SVt_PVCV)
- break;
- /* FALL THROUGH */
- case SVt_PVHV:
- case SVt_PVAV:
+ if (UNLIKELY(!sv))
DIE(aTHX_ "Not a CODE reference");
- /* This is the second most common case: */
- case SVt_PVCV:
- cv = MUTABLE_CV(sv);
- break;
+ /* This is overwhelmingly the most common case: */
+ if (!LIKELY(SvTYPE(sv) == SVt_PVGV && (cv = GvCVu((const GV *)sv)))) {
+ switch (SvTYPE(sv)) {
+ case SVt_PVGV:
+ we_have_a_glob:
+ if (!(cv = GvCVu((const GV *)sv))) {
+ HV *stash;
+ cv = sv_2cv(sv, &stash, &gv, 0);
+ }
+ if (!cv) {
+ ENTER;
+ SAVETMPS;
+ goto try_autoload;
+ }
+ break;
+ case SVt_PVLV:
+ if(isGV_with_GP(sv)) goto we_have_a_glob;
+ /*FALLTHROUGH*/
+ default:
+ if (sv == &PL_sv_yes) { /* unfound import, ignore */
+ if (hasargs)
+ SP = PL_stack_base + POPMARK;
+ else
+ (void)POPMARK;
+ RETURN;
+ }
+ SvGETMAGIC(sv);
+ if (SvROK(sv)) {
+ if (SvAMAGIC(sv)) {
+ sv = amagic_deref_call(sv, to_cv_amg);
+ /* Don't SPAGAIN here. */
+ }
+ }
+ else {
+ const char *sym;
+ STRLEN len;
+ if (!SvOK(sv))
+ DIE(aTHX_ PL_no_usym, "a subroutine");
+ sym = SvPV_nomg_const(sv, len);
+ if (PL_op->op_private & HINT_STRICT_REFS)
+ DIE(aTHX_ "Can't use string (\"%" SVf32 "\"%s) as a subroutine ref while \"strict refs\" in use", sv, len>32 ? "..." : "");
+ cv = get_cvn_flags(sym, len, GV_ADD|SvUTF8(sv));
+ break;
+ }
+ cv = MUTABLE_CV(SvRV(sv));
+ if (SvTYPE(cv) == SVt_PVCV)
+ break;
+ /* FALL THROUGH */
+ case SVt_PVHV:
+ case SVt_PVAV:
+ DIE(aTHX_ "Not a CODE reference");
+ /* This is the second most common case: */
+ case SVt_PVCV:
+ cv = MUTABLE_CV(sv);
+ break;
+ }
}
ENTER;
retry:
- if (CvCLONE(cv) && ! CvCLONED(cv))
+ if (UNLIKELY(CvCLONE(cv) && ! CvCLONED(cv)))
DIE(aTHX_ "Closure prototype called");
- if (!CvROOT(cv) && !CvXSUB(cv)) {
+ if (UNLIKELY(!CvROOT(cv) && !CvXSUB(cv))) {
GV* autogv;
SV* sub_name;
@@ -2621,8 +2626,9 @@ try_autoload:
goto retry;
}
- gimme = GIMME_V;
- if ((PL_op->op_private & OPpENTERSUB_DB) && GvCV(PL_DBsub) && !CvNODEBUG(cv)) {
+ if (UNLIKELY((PL_op->op_private & OPpENTERSUB_DB) && GvCV(PL_DBsub)
+ && !CvNODEBUG(cv)))
+ {
Perl_get_db_sub(aTHX_ &sv, cv);
if (CvISXSUB(cv))
PL_curcopdb = PL_curcop;
@@ -2639,37 +2645,43 @@ try_autoload:
DIE(aTHX_ "No DB::sub routine defined");
}
+ gimme = GIMME_V;
+
if (!(CvISXSUB(cv))) {
/* This path taken at least 75% of the time */
dMARK;
- SSize_t items = SP - MARK;
PADLIST * const padlist = CvPADLIST(cv);
+ I32 depth;
+
PUSHBLOCK(cx, CXt_SUB, MARK);
PUSHSUB(cx);
cx->blk_sub.retop = PL_op->op_next;
- CvDEPTH(cv)++;
- if (CvDEPTH(cv) >= 2) {
+ if (UNLIKELY((depth = ++CvDEPTH(cv)) >= 2)) {
PERL_STACK_OVERFLOW_CHECK();
- pad_push(padlist, CvDEPTH(cv));
+ pad_push(padlist, depth);
}
SAVECOMPPAD();
- PAD_SET_CUR_NOSAVE(padlist, CvDEPTH(cv));
- if (hasargs) {
+ PAD_SET_CUR_NOSAVE(padlist, depth);
+ if (LIKELY(hasargs)) {
AV *const av = MUTABLE_AV(PAD_SVl(0));
- if (AvREAL(av)) {
+ SSize_t items;
+ AV **defavp;
+
+ if (UNLIKELY(AvREAL(av))) {
/* @_ is normally not REAL--this should only ever
* happen when DB::sub() calls things that modify @_ */
av_clear(av);
AvREAL_off(av);
AvREIFY_on(av);
}
- cx->blk_sub.savearray = GvAV(PL_defgv);
- GvAV(PL_defgv) = MUTABLE_AV(SvREFCNT_inc_simple(av));
+ defavp = &GvAV(PL_defgv);
+ cx->blk_sub.savearray = *defavp;
+ *defavp = MUTABLE_AV(SvREFCNT_inc_simple_NN(av));
CX_CURPAD_SAVE(cx->blk_sub);
cx->blk_sub.argarray = av;
- ++MARK;
+ items = SP - MARK;
- if (items - 1 > AvMAX(av)) {
+ if (UNLIKELY(items - 1 > AvMAX(av))) {
SV **ary = AvALLOC(av);
AvMAX(av) = items - 1;
Renew(ary, items, SV*);
@@ -2677,30 +2689,33 @@ try_autoload:
AvARRAY(av) = ary;
}
- Copy(MARK,AvARRAY(av),items,SV*);
+ Copy(MARK+1,AvARRAY(av),items,SV*);
AvFILLp(av) = items - 1;
MARK = AvARRAY(av);
while (items--) {
if (*MARK)
{
- if (SvPADTMP(*MARK) && !IS_PADGV(*MARK))
+ if (SvPADTMP(*MARK)) {
+ assert(!IS_PADGV(*MARK));
*MARK = sv_mortalcopy(*MARK);
+ }
SvTEMP_off(*MARK);
}
MARK++;
}
}
SAVETMPS;
- if ((cx->blk_u16 & OPpENTERSUB_LVAL_MASK) == OPpLVAL_INTRO &&
- !CvLVALUE(cv))
+ if (UNLIKELY((cx->blk_u16 & OPpENTERSUB_LVAL_MASK) == OPpLVAL_INTRO &&
+ !CvLVALUE(cv)))
DIE(aTHX_ "Can't modify non-lvalue subroutine call");
/* warning must come *after* we fully set up the context
* stuff so that __WARN__ handlers can safely dounwind()
* if they want to
*/
- if (CvDEPTH(cv) == PERL_SUB_DEPTH_WARN && ckWARN(WARN_RECURSION)
- && !(PERLDB_SUB && cv == GvCV(PL_DBsub)))
+ if (UNLIKELY(depth == PERL_SUB_DEPTH_WARN
+ && ckWARN(WARN_RECURSION)
+ && !(PERLDB_SUB && cv == GvCV(PL_DBsub))))
sub_crush_depth(cv);
RETURNOP(CvSTART(cv));
}
@@ -2710,13 +2725,13 @@ try_autoload:
SAVETMPS;
PUTBACK;
- if (((PL_op->op_private
+ if (UNLIKELY(((PL_op->op_private
& PUSHSUB_GET_LVALUE_MASK(Perl_is_lvalue_sub)
) & OPpENTERSUB_LVAL_MASK) == OPpLVAL_INTRO &&
- !CvLVALUE(cv))
+ !CvLVALUE(cv)))
DIE(aTHX_ "Can't modify non-lvalue subroutine call");
- if (!hasargs && GvAV(PL_defgv)) {
+ if (UNLIKELY(!hasargs && GvAV(PL_defgv))) {
/* Need to copy @_ to stack. Alternative may be to
* switch stack to @_, and copy return values
* back. This would allow popping @_ in XSUB, e.g.. XXXX */
@@ -2750,12 +2765,14 @@ try_autoload:
SSize_t items = SP - mark;
while (items--) {
mark++;
- if (*mark && SvPADTMP(*mark) && !IS_PADGV(*mark))
+ if (*mark && SvPADTMP(*mark)) {
+ assert(!IS_PADGV(*mark));
*mark = sv_mortalcopy(*mark);
+ }
}
}
/* We assume first XSUB in &DB::sub is the called one. */
- if (PL_curcopdb) {
+ if (UNLIKELY(PL_curcopdb)) {
SAVEVPTR(PL_curcop);
PL_curcop = PL_curcopdb;
PL_curcopdb = NULL;
@@ -2767,12 +2784,12 @@ try_autoload:
CvXSUB(cv)(aTHX_ cv);
/* Enforce some sanity in scalar context. */
- if (gimme == G_SCALAR && ++markix != PL_stack_sp - PL_stack_base ) {
- if (markix > PL_stack_sp - PL_stack_base)
- *(PL_stack_base + markix) = &PL_sv_undef;
- else
- *(PL_stack_base + markix) = *PL_stack_sp;
- PL_stack_sp = PL_stack_base + markix;
+ if (gimme == G_SCALAR) {
+ SV **svp = PL_stack_base + markix + 1;
+ if (svp != PL_stack_sp) {
+ *svp = svp > PL_stack_sp ? &PL_sv_undef : *PL_stack_sp;
+ PL_stack_sp = svp;
+ }
}
LEAVE;
return NORMAL;
diff --git a/pp_sort.c b/pp_sort.c
index ae0c9c1a57..4741d71dbd 100644
--- a/pp_sort.c
+++ b/pp_sort.c
@@ -1609,8 +1609,10 @@ PP(pp_sort)
copytmps = !sorting_av && PL_sortcop;
for (i=max; i > 0 ; i--) {
if ((*p1 = *p2++)) { /* Weed out nulls. */
- if (copytmps && SvPADTMP(*p1) && !IS_PADGV(*p1))
+ if (copytmps && SvPADTMP(*p1)) {
+ assert(!IS_PADGV(*p1));
*p1 = sv_mortalcopy(*p1);
+ }
SvTEMP_off(*p1);
if (!PL_sortcop) {
if (priv & OPpSORT_NUMERIC) {
diff --git a/regexec.c b/regexec.c
index 6dd029747c..df27193990 100644
--- a/regexec.c
+++ b/regexec.c
@@ -2528,13 +2528,14 @@ Perl_regexec_flags(pTHX_ REGEXP * const rx, char *stringarg, char *strend,
/* see how far we have to get to not match where we matched before */
reginfo->till = stringarg + minend;
- if (prog->extflags & RXf_EVAL_SEEN && SvPADTMP(sv) && !IS_PADGV(sv)) {
+ if (prog->extflags & RXf_EVAL_SEEN && SvPADTMP(sv)) {
/* SAVEFREESV, not sv_mortalcopy, as this SV must last until after
S_cleanup_regmatch_info_aux has executed (registered by
SAVEDESTRUCTOR_X below). S_cleanup_regmatch_info_aux modifies
magic belonging to this SV.
Not newSVsv, either, as it does not COW.
*/
+ assert(!IS_PADGV(sv));
reginfo->sv = newSV(0);
SvSetSV_nosteal(reginfo->sv, sv);
SAVEFREESV(reginfo->sv);