diff options
author | syber <syber@crazypanda.ru> | 2014-11-28 21:22:25 +0300 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2014-11-28 18:10:58 -0800 |
commit | 7d6c333c75cb0519428c389de3894edcb394d3a0 (patch) | |
tree | d03a03a0aaa68b1a8348aea290600d0d7bee4e48 /pp_hot.c | |
parent | 5ec005187f9529697da2ef026ddf0a3758600148 (diff) | |
download | perl-7d6c333c75cb0519428c389de3894edcb394d3a0.tar.gz |
speedup for SUPER::method() calls.
In ck_method:
Scan for '/::. If found SUPER::, create OP_METHOD_SUPER op
with precomputed hash value for method name.
In B::*, added support for method_super
In pp_hot.c, pp_method_*:
S_method_common removed, code related to getting stash is
moved to S_opmethod_stash, other code is moved to
pp_method_* functions.
As a result, SUPER::func() calls speeded up by 50%.
Diffstat (limited to 'pp_hot.c')
-rw-r--r-- | pp_hot.c | 140 |
1 files changed, 86 insertions, 54 deletions
@@ -2973,40 +2973,11 @@ Perl_vivify_ref(pTHX_ SV *sv, U32 to_what) return sv; } -PP(pp_method) -{ - dSP; - SV* const sv = TOPs; - - if (SvROK(sv)) { - SV* const rsv = SvRV(sv); - if (SvTYPE(rsv) == SVt_PVCV) { - SETs(rsv); - RETURN; - } - } - - SETs(method_common(sv, NULL)); - RETURN; -} - -PP(pp_method_named) -{ - dSP; - SV* const meth = cMETHOPx_meth(PL_op); - U32 hash = SvSHARED_HASH(meth); - - XPUSHs(method_common(meth, &hash)); - RETURN; -} - -STATIC SV * -S_method_common(pTHX_ SV* meth, U32* hashp) +PERL_STATIC_INLINE HV * +S_opmethod_stash(pTHX_ SV* meth) { SV* ob; - GV* gv; HV* stash; - SV *packsv = NULL; SV* const sv = PL_stack_base + TOPMARK == PL_stack_sp ? (Perl_croak(aTHX_ "Can't call method \"%"SVf"\" without a " @@ -3014,7 +2985,7 @@ S_method_common(pTHX_ SV* meth, U32* hashp) (SV *)NULL) : *(PL_stack_base + TOPMARK + 1); - PERL_ARGS_ASSERT_METHOD_COMMON; + PERL_ARGS_ASSERT_OPMETHOD_STASH; if (UNLIKELY(!sv)) undefined: @@ -3024,7 +2995,7 @@ S_method_common(pTHX_ SV* meth, U32* hashp) if (UNLIKELY(SvGMAGICAL(sv))) mg_get(sv); else if (SvIsCOW_shared_hash(sv)) { /* MyClass->meth() */ stash = gv_stashsv(sv, GV_CACHE_ONLY); - if (stash) goto fetch; + if (stash) return stash; } if (SvROK(sv)) @@ -3050,7 +3021,7 @@ S_method_common(pTHX_ SV* meth, U32* hashp) const char * const packname = SvPV_nomg_const(sv, packlen); const U32 packname_utf8 = SvUTF8(sv); stash = gv_stashpvn(packname, packlen, packname_utf8 | GV_CACHE_ONLY); - if (stash) goto fetch; + if (stash) return stash; if (!(iogv = gv_fetchpvn_flags( packname, packlen, packname_utf8, SVt_PVIO @@ -3066,8 +3037,8 @@ S_method_common(pTHX_ SV* meth, U32* hashp) } /* assume it's a package name */ stash = gv_stashpvn(packname, packlen, packname_utf8); - if (!stash) packsv = sv; - goto fetch; + if (stash) return stash; + else return MUTABLE_HV(sv); } /* it _is_ a filehandle name -- replace with a reference */ *(PL_stack_base + TOPMARK + 1) = sv_2mortal(newRV(MUTABLE_SV(iogv))); @@ -3085,31 +3056,92 @@ S_method_common(pTHX_ SV* meth, U32* hashp) : meth)); } - stash = SvSTASH(ob); + return SvSTASH(ob); +} + +PP(pp_method) +{ + dSP; + GV* gv; + HV* stash; + SV* const meth = TOPs; + + if (SvROK(meth)) { + SV* const rmeth = SvRV(meth); + if (SvTYPE(rmeth) == SVt_PVCV) { + SETs(rmeth); + RETURN; + } + } - fetch: - /* NOTE: stash may be null, hope hv_fetch_ent and - gv_fetchmethod can cope (it seems they can) */ + stash = opmethod_stash(meth); - /* shortcut for simple names */ - if (hashp) { - const HE* const he = hv_fetch_ent(stash, meth, 0, *hashp); - if (he) { - gv = MUTABLE_GV(HeVAL(he)); - assert(stash); - if (isGV(gv) && GvCV(gv) && - (!GvCVGEN(gv) || GvCVGEN(gv) + gv = gv_fetchmethod_sv_flags(stash, meth, GV_AUTOLOAD|GV_CROAK); + assert(gv); + + SETs(isGV(gv) ? MUTABLE_SV(GvCV(gv)) : MUTABLE_SV(gv)); + RETURN; +} + +PP(pp_method_named) +{ + dSP; + GV* gv; + SV* const meth = cMETHOPx_meth(PL_op); + HV* const stash = opmethod_stash(meth); + + if (LIKELY(SvTYPE(stash) == SVt_PVHV)) { + const HE* const he = hv_fetch_ent(stash, meth, 0, 0); + if (he) { + gv = MUTABLE_GV(HeVAL(he)); + if (isGV(gv) && GvCV(gv) && + (!GvCVGEN(gv) || GvCVGEN(gv) == (PL_sub_generation + HvMROMETA(stash)->cache_gen))) - return MUTABLE_SV(GvCV(gv)); - } + { + XPUSHs(MUTABLE_SV(GvCV(gv))); + RETURN; + } + } } - assert(stash || packsv); - gv = gv_fetchmethod_sv_flags(stash ? stash : MUTABLE_HV(packsv), - meth, GV_AUTOLOAD | GV_CROAK); + gv = gv_fetchmethod_sv_flags(stash, meth, GV_AUTOLOAD|GV_CROAK); assert(gv); - return isGV(gv) ? MUTABLE_SV(GvCV(gv)) : MUTABLE_SV(gv); + XPUSHs(isGV(gv) ? MUTABLE_SV(GvCV(gv)) : MUTABLE_SV(gv)); + RETURN; +} + +PP(pp_method_super) +{ + dSP; + GV* gv; + HV* cache; + SV* const meth = cMETHOPx_meth(PL_op); + HV* const stash = CopSTASH(PL_curcop); + /* Actually, SUPER doesn't need real object's (or class') stash at all, + * as it uses CopSTASH. However, we must ensure that object(class) is + * correct (this check is done by S_opmethod_stash) */ + opmethod_stash(meth); + + if ((cache = HvMROMETA(stash)->super)) { + const HE* const he = hv_fetch_ent(cache, meth, 0, 0); + if (he) { + gv = MUTABLE_GV(HeVAL(he)); + if (isGV(gv) && GvCV(gv) && + (!GvCVGEN(gv) || GvCVGEN(gv) + == (PL_sub_generation + HvMROMETA(stash)->cache_gen))) + { + XPUSHs(MUTABLE_SV(GvCV(gv))); + RETURN; + } + } + } + + gv = gv_fetchmethod_sv_flags(stash, meth, GV_AUTOLOAD|GV_CROAK|GV_SUPER); + assert(gv); + + XPUSHs(isGV(gv) ? MUTABLE_SV(GvCV(gv)) : MUTABLE_SV(gv)); + RETURN; } /* |