#include "EXTERN.h" #include "perl.h" #include "embed.h" #include "XSUB.h" typedef OP *B__OP; struct inlined_cv { SV sv; OP *inlined; OP *entersub; OP *revert; }; OP * Method_Inline_inlined (pTHX) { dSP; dTOPss; GV *gv; register CV *cv; struct inlined_cv *i = (struct inlined_cv *)cSVOP_sv; /* this is a butchered ENTERSUB * uncomment to enable caching of subs too, not just methods */ #if 0 if (!sv) DIE(aTHX_ "Not a CODE reference"); switch (SvTYPE(sv)) { /* This is overwhelming the most common case: */ case SVt_PVGV: if (!(cv = GvCVu((GV*)sv))) { HV *stash; cv = sv_2cv(sv, &stash, &gv, 0); } break; default: if (!SvROK(sv)) { const char *sym; STRLEN len; if (sv == &PL_sv_yes) { /* unfound import, ignore */ if (hasargs) SP = PL_stack_base + POPMARK; RETURN; } if (SvGMAGICAL(sv)) { mg_get(sv); if (SvROK(sv)) goto got_rv; if (SvPOKp(sv)) { sym = SvPVX_const(sv); len = SvCUR(sv); } else { sym = NULL; len = 0; } } else { sym = SvPV_const(sv, len); } if (!sym) DIE(aTHX_ PL_no_usym, "a subroutine"); if (PL_op->op_private & HINT_STRICT_REFS) DIE(aTHX_ PL_no_symref, sym, "a subroutine"); cv = get_cvn_flags(sym, len, GV_ADD|SvUTF8(sv)); break; } got_rv: { SV * const * sp = &sv; /* Used in tryAMAGICunDEREF macro. */ tryAMAGICunDEREF(to_cv); } cv = (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 = (CV*)sv; break; } #else if (SvTYPE(sv) == SVt_PVCV) { cv = (CV*)sv; } #endif if ( SvANY(&i->sv) == SvANY(cv) ) { RETURNOP(i->inlined); } else { /* save some work for ENTERSUB if possible * disabled because the above is if (cv) SETs((SV *)cv) */ // i->revert->op_next = i->entersub; RETURNOP(i->entersub); } } OP * Method_Inline_create_inlined (pTHX_ CV* cv, OP *inlined, OP *entersub, OP *prev) { struct inlined_cv *i; OP *op; /* create our fake SV */ Newx(i, 1, struct inlined_cv); i->sv = *(SV *)cv; SvREFCNT_inc(&i->sv); i->entersub = entersub; i->inlined = inlined; i->revert = prev; op = newSVOP( OP_CUSTOM, 0, (SV *)i ); op->op_ppaddr = Method_Inline_inlined; op->op_next = entersub->op_next; return op; } MODULE = Method::Inline PACKAGE = Method::Inline void inlined_op(CV *cv, B::OP inlined, B::OP entersub, B::OP prev) OP *o = NO_INIT CODE: { o = Method_Inline_create_inlined(aTHX_ cv, inlined, entersub, prev); ST(0) = sv_newmortal(); sv_setiv(newSVrv(ST(0), "B::OP"), PTR2IV(o)); } IV inline_op_pp_addr () CODE: { RETVAL = PTR2IV(Method_Inline_inlined); }