Re-order CV flags to bring the 4 CVf_BUILTIN_ATTRS into adjacent bits,
[p5sagit/p5-mst-13.2.git] / ext / Devel / DProf / DProf.xs
index caa0729..02396e9 100644 (file)
 #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);