X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=ext%2FDevel%2FDProf%2FDProf.xs;h=02396e94b6aa291c94d2ccf4a035fa0e590a5081;hb=5b4563c8796d609e1b00a7e3af7630b7fee611ae;hp=caa07293c199815fb5176a510beaf7a3079c0f2e;hpb=ae7638f4d1ab4edf2eef64922c6d042904d21153;p=p5sagit%2Fp5-mst-13.2.git diff --git a/ext/Devel/DProf/DProf.xs b/ext/Devel/DProf/DProf.xs index caa0729..02396e9 100644 --- a/ext/Devel/DProf/DProf.xs +++ b/ext/Devel/DProf/DProf.xs @@ -15,16 +15,35 @@ #define ASSERT(x) #endif +static CV * +db_get_cv(pTHX_ SV *sv) +{ + CV *cv; + + if (SvIOK(sv)) { /* if (PERLDB_SUB_NN) { */ + cv = INT2PTR(CV*,SvIVX(sv)); + } else { + if (SvPOK(sv)) { + cv = get_cv(SvPVX_const(sv), TRUE); + } else if (SvROK(sv)) { + cv = (CV*)SvRV(sv); + } else { + croak("DProf: don't know what subroutine to profile"); + } + } + return cv; +} + #ifdef DBG_SUB -# define DBG_SUB_NOTIFY(A) dprof_dbg_sub_notify(A) +# define DBG_SUB_NOTIFY(A) dprof_dbg_sub_notify(aTHX_ A) void -dprof_dbg_sub_notify(SV *Sub) { - CV *cv = INT2PTR(CV*,SvIVX(Sub)); +dprof_dbg_sub_notify(pTHX_ SV *Sub) { + CV *cv = db_get_cv(aTHX_ Sub); GV *gv = cv ? CvGV(cv) : NULL; if (cv && gv) { warn("XS DBsub(%s::%s)\n", - ((GvSTASH(gv) && HvNAME(GvSTASH(gv))) ? - HvNAME(GvSTASH(gv)) : "(null)"), + ((GvSTASH(gv) && HvNAME_get(GvSTASH(gv))) ? + HvNAME_get(GvSTASH(gv)) : "(null)"), GvNAME(gv)); } else { warn("XS DBsub(unknown) at %x", Sub); @@ -106,7 +125,8 @@ typedef struct { PROFANY* profstack; int profstack_max; int profstack_ix; - HV* cv_hash; + HV* cv_hash; /* cache of CV to identifier mappings */ + SV* key_hash; /* key for cv_hash */ U32 total; U32 lastid; U32 default_perldb; @@ -116,9 +136,7 @@ typedef struct { long long start_cnt; #endif #ifdef PERL_IMPLICIT_CONTEXT -# define register - pTHX; -# undef register + PerlInterpreter *my_perl; #endif } prof_state_t; @@ -144,12 +162,13 @@ prof_state_t g_prof_state; #define g_profstack_max g_prof_state.profstack_max #define g_profstack_ix g_prof_state.profstack_ix #define g_cv_hash g_prof_state.cv_hash +#define g_key_hash g_prof_state.key_hash #define g_total g_prof_state.total #define g_lastid g_prof_state.lastid #define g_default_perldb g_prof_state.default_perldb #define g_depth g_prof_state.depth #ifdef PERL_IMPLICIT_CONTEXT -# define g_THX g_prof_state.aTHX +# define g_THX g_prof_state.my_perl #endif #ifdef OS2 # define g_frequ g_prof_state.frequ @@ -162,7 +181,6 @@ dprof_times(pTHX_ struct tms *t) #ifdef OS2 ULONG rc; QWORD cnt; - STRLEN n_a; if (!g_frequ) { if (CheckOSError(DosTmrQueryFreq(&g_frequ))) @@ -171,7 +189,7 @@ dprof_times(pTHX_ struct tms *t) g_frequ = g_frequ/DPROF_HZ; /* count per tick */ if (CheckOSError(DosTmrQueryTime(&cnt))) croak("DosTmrQueryTime: %s", - SvPV(perl_get_sv("!",TRUE), n_a)); + SvPV_nolen_const(perl_get_sv("!",TRUE))); g_start_cnt = toLongLong(cnt); } @@ -295,6 +313,16 @@ prof_dump_until(pTHX_ long ix) } static void +set_cv_key(pTHX_ CV *cv, char *pname, char *gname) +{ + SvGROW(g_key_hash, sizeof(CV**) + strlen(pname) + strlen(gname) + 3); + sv_setpvn(g_key_hash, (char*)&cv, sizeof(CV**)); + sv_catpv(g_key_hash, pname); + sv_catpv(g_key_hash, "::"); + sv_catpv(g_key_hash, gname); +} + +static void prof_mark(pTHX_ opcode ptype) { struct tms t; @@ -336,17 +364,18 @@ prof_mark(pTHX_ opcode ptype) SV **svp; char *gname, *pname; CV *cv; + GV *gv; - cv = INT2PTR(CV*,SvIVX(Sub)); - svp = hv_fetch(g_cv_hash, (char*)&cv, sizeof(CV*), TRUE); + cv = db_get_cv(aTHX_ Sub); + gv = CvGV(cv); + pname = GvSTASH(gv) ? HvNAME_get(GvSTASH(gv)) : 0; + pname = pname ? pname : (char *) "(null)"; + gname = GvNAME(gv); + + set_cv_key(aTHX_ cv, pname, gname); + svp = hv_fetch(g_cv_hash, SvPVX_const(g_key_hash), SvCUR(g_key_hash), TRUE); if (!SvOK(*svp)) { - GV *gv = CvGV(cv); - sv_setiv(*svp, id = ++g_lastid); - pname = ((GvSTASH(gv) && HvNAME(GvSTASH(gv))) - ? HvNAME(GvSTASH(gv)) - : "(null)"); - gname = GvNAME(gv); if (CvXSUB(cv) == XS_Devel__DProf_END) return; if (g_SAVE_STACK) { /* Store it for later recording -JH */ @@ -547,12 +576,14 @@ XS(XS_DB_sub) /* profile only the interpreter that loaded us */ if (g_THX != aTHX) { PUSHMARK(ORIGMARK); - perl_call_sv(INT2PTR(SV*,SvIV(Sub)), GIMME_V | G_NODEBUG); + perl_call_sv((SV*)db_get_cv(aTHX_ Sub), GIMME_V | G_NODEBUG); } else #endif { HV *oldstash = PL_curstash; + I32 old_scopestack_ix = PL_scopestack_ix; + I32 old_cxstack_ix = cxstack_ix; DBG_SUB_NOTIFY(Sub); @@ -561,8 +592,16 @@ XS(XS_DB_sub) prof_mark(aTHX_ OP_ENTERSUB); PUSHMARK(ORIGMARK); - perl_call_sv(INT2PTR(SV*,SvIV(Sub)), GIMME_V | G_NODEBUG); + perl_call_sv((SV*)db_get_cv(aTHX_ Sub), GIMME_V | G_NODEBUG); PL_curstash = oldstash; + + /* Make sure we are on the same context and scope as before the call + * to the sub. If the called sub was exited via a goto, next or + * last then this will try to croak(), however perl may still crash + * with a segfault. */ + if (PL_scopestack_ix != old_scopestack_ix || cxstack_ix != old_cxstack_ix) + croak("panic: Devel::DProf inconsistent subroutine return"); + prof_mark(aTHX_ OP_LEAVESUB); g_depth--; } @@ -693,9 +732,10 @@ BOOT: g_default_perldb = PERLDBf_NONAME | PERLDBf_SUB | PERLDBf_GOTO; g_cv_hash = newHV(); + g_key_hash = newSV(256); g_prof_pid = (int)getpid(); - New(0, g_profstack, g_profstack_max, PROFANY); + Newx(g_profstack, g_profstack_max, PROFANY); prof_recordheader(aTHX); DBG_TIMER_NOTIFY("Profiler timer is on.\n"); g_orealtime = g_rprof_start = Times(&g_prof_start);