Skip to content

Commit 35482d4

Browse files
committed
op_dump(): display SVs on threaded builds
Some OPs, such as OP_CONST, OP_GVSV and OP_METHOD_NAMED, point to an SV or GV. In threaded builds, these SVs are moved to the pad and an index is stored in the OP instead (typically op_targ or op_padix). When op_dump() is called upon to display an OP (typically during debugging or via perl -Dx), then currently, information about the linked SV (e.g. the glob's name) is displayed only on non-threaded builds, since op_dump() can't assume that PL_curpad[] is associated with this particular op. Thus you get things like an OP_CONST being dumped that doesn't display the const's value. This is annoying during debugging. This commit makes it so that when dumping common OPs which have an SV in the pad, it tries to find the CV, if any, associated with that op, and if so, uses that CV's pad to lookup the value. If unsuccessful, it falls back to not displaying the SV. This commit uses two main techniques to find the CV. Both rely on first following the op_parent chain from the current op to find the root op of the optree which this op is embedded in. Then, if compiling, it compares this with the roots of the optrees currently on the parse stack, and so, uses the associated CV which is is pointed to from that slot on the parse stack. Or, if runtime, looks for a SUB or EVAL context on the context stack and sees if that sub or eval's CvROOT() / PL_eval_root matches the root of the op's tree. The next two commits will extend this to handle 'perl -Dx' too. This commit also tries to show the state of the fields on CONST and METHOD_FOO ops which can hold an SV or index, in addition to showing the SV that is retrieved from them. Here are examples of some op dumps on threaded builds before and after this commit: -------------------------------------------------------------- const SVOP(0x2a051578) ===> 6 [gvsv 0x2a0515e8] TARG = 2 FLAGS = (SCALAR,SLABBED,MORESIB) gvsv PADOP(0x2a0515e8) ===> 5 [sassign 0x2a051538] FLAGS = (SCALAR,SLABBED) PADIX = 1 method_redir METHOP(0x13dd4318) ===> 5 [entersub 0x13dd4358] TARG = 4 FLAGS = (UNKNOWN,SLABBED) -------------------------------------------------------------- const SVOP(0x22f655b8) ===> 6 [gvsv 0x22f65628] TARG = 2 FLAGS = (SCALAR,SLABBED,MORESIB) OP_SV = 0x0 SV = PV("abc"\0) (0x22f65768) gvsv PADOP(0x22f65628) ===> 5 [sassign 0x22f65578] FLAGS = (SCALAR,SLABBED) PADIX = 1 GV = main::x (0x22f58f20) method_redir METHOP(0x1d83f318) ===> 5 [entersub 0x1d83f358] TARG = 4 FLAGS = (UNKNOWN,SLABBED) OP_METH_SV = 0x0 METH = PV("foo") (0x1d833010) RCLASS_TARG = 2 RCLASS = PV("BAR") (0x1d83f638) --------------------------------------------------------------
1 parent f42dd5f commit 35482d4

File tree

1 file changed

+173
-21
lines changed

1 file changed

+173
-21
lines changed

dump.c

Lines changed: 173 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,6 +1093,123 @@ S_pm_description(pTHX_ const PMOP *pm)
10931093
return desc;
10941094
}
10951095

1096+
1097+
/* S_get_sv_from_pad(): a helper function for op_dump().
1098+
*
1099+
* On threaded builds, try to find the SV indexed by the OP o (e.g. via
1100+
* op_targ or op_padix) at pad offset po.
1101+
* Since an op can be dumped at any time, there is no guarantee that the
1102+
* OP is associated with the current PL_curpad. So try to find the currently
1103+
* running CV or eval, and see if it contains the OP. Or if it's
1104+
* compile-time, see if the op is contained within one of the op subtrees
1105+
* on the parser stack.
1106+
*
1107+
* Return NULL if it can't be found.
1108+
*
1109+
* Since this may be called during debugging and things may not be in a
1110+
* sane state, be conservative, and if in doubt, return NULL.
1111+
*/
1112+
1113+
#ifdef USE_ITHREADS
1114+
static SV *
1115+
S_get_sv_from_pad(pTHX_ const OP *o, PADOFFSET po)
1116+
{
1117+
PADLIST *padlist; /* declare early to work round compiler quirks */
1118+
1119+
if (!po)
1120+
return NULL;
1121+
1122+
CV *cv = NULL;
1123+
1124+
/* Find the root of the optree this op is embedded in. For a compiled
1125+
* sub, this root will typically be a leavesub or similar attached to
1126+
* a CV. If compiling, this may be a small subtree on the parser
1127+
* stack. Limit the number of hops, in case there is some sort of
1128+
* loop or other weirdness.
1129+
*/
1130+
int n = 100;
1131+
OP *oproot = (OP*)o;
1132+
while (1) {
1133+
if (--n <= 0)
1134+
return NULL;
1135+
OP *p = op_parent(oproot);
1136+
if (!p)
1137+
break;
1138+
oproot = p;
1139+
}
1140+
1141+
/* We may be compiling; so first look for the op within the subtrees
1142+
* on the parse stack, if any */
1143+
if (PL_parser && PL_parser->stack) {
1144+
yy_stack_frame *ps;
1145+
1146+
for (ps = PL_parser->ps; ps > PL_parser->stack; ps--) {
1147+
if (ps->val.opval == oproot) {
1148+
cv = ps->compcv;
1149+
if (!cv)
1150+
return NULL; /* this shouldn't actually happen */
1151+
goto got_cv;
1152+
}
1153+
}
1154+
}
1155+
1156+
/* Find the currently running CV or eval, if any, and see if our op
1157+
* is part of that CV's optree. If no contexts are found, we're
1158+
* probably running the main program.
1159+
*/
1160+
I32 i;
1161+
for (i = cxstack_ix; i >= 0; i--) {
1162+
const PERL_CONTEXT * const cx = &cxstack[i];
1163+
switch (CxTYPE(cx)) {
1164+
default:
1165+
continue;
1166+
case CXt_EVAL:
1167+
if (CxTRY(cx)) /* eval { } doesn't have a separate optree */
1168+
continue;
1169+
cv = cxstack[i].blk_eval.cv;
1170+
/* XXX note that an EVAL's CV doesn't actually hold a pointer
1171+
* to the optree's root; we have to hope that PL_eval_root
1172+
* does instead */
1173+
if (!cv || !CvEVAL(cv) || oproot != PL_eval_root)
1174+
continue;
1175+
goto got_cv;
1176+
case CXt_SUB:
1177+
if (cx->cx_type & CXp_SUB_RE_FAKE)
1178+
continue;
1179+
/* FALLTHROUGH */
1180+
case CXt_FORMAT:
1181+
cv = cxstack[i].blk_sub.cv;
1182+
if (!cv || CvISXSUB(cv) || oproot != CvROOT(cv))
1183+
continue;
1184+
goto got_cv;
1185+
}
1186+
}
1187+
1188+
if (PL_main_cv && PL_main_root == oproot) {
1189+
cv = PL_main_cv;
1190+
goto got_cv;
1191+
}
1192+
return NULL;
1193+
1194+
/* Lookup the entry in the pad associated with this CV.
1195+
* Note that for SVs moved into the pad, they are shared at all pad
1196+
* depths, so we only have to look at depth 1 and not worry about
1197+
* CvDEPTH(). */
1198+
got_cv:
1199+
padlist = CvPADLIST(cv);
1200+
if (!padlist)
1201+
return NULL;
1202+
PAD *comppad = PadlistARRAY(padlist)[1];
1203+
if (!comppad)
1204+
return NULL;
1205+
SV **curpad = AvARRAY(comppad);
1206+
if (!curpad)
1207+
return NULL;
1208+
return curpad[po];
1209+
}
1210+
#endif
1211+
1212+
10961213
/*
10971214
=for apidoc pmop_dump
10981215
@@ -1346,15 +1463,21 @@ S_do_op_dump_bar(pTHX_ I32 level, UV bar, PerlIO *file, const OP *o)
13461463
case OP_AELEMFAST:
13471464
case OP_GVSV:
13481465
case OP_GV:
1466+
{
1467+
GV *gv;
13491468
#ifdef USE_ITHREADS
13501469
S_opdump_indent(aTHX_ o, level, bar, file,
13511470
"PADIX = %" IVdf "\n", (IV)cPADOPo->op_padix);
1471+
gv = (GV*)S_get_sv_from_pad(aTHX_ o, cPADOPx(o)->op_padix);
13521472
#else
1353-
S_opdump_indent(aTHX_ o, level, bar, file,
1354-
"GV = %" SVf " (0x%" UVxf ")\n",
1355-
SVfARG(S_gv_display(aTHX_ cGVOPo_gv)), PTR2UV(cGVOPo_gv));
1473+
gv = (GV*)cSVOPx(o)->op_sv;
13561474
#endif
1475+
if (gv)
1476+
S_opdump_indent(aTHX_ o, level, bar, file,
1477+
"GV = %" SVf " (0x%" UVxf ")\n",
1478+
SVfARG(S_gv_display(aTHX_ gv)), PTR2UV(gv));
13571479
break;
1480+
}
13581481

13591482
case OP_MULTIDEREF:
13601483
{
@@ -1388,15 +1511,23 @@ S_do_op_dump_bar(pTHX_ I32 level, UV bar, PerlIO *file, const OP *o)
13881511
* op_relocate_sv() and indexed by op_targ.
13891512
* XXX Currently the SV isn't relocated for OP_COREARGS.
13901513
*/
1391-
S_opdump_indent(aTHX_ o, level, bar, file,
1392-
"OP_SV = 0x%" UVxf "\n", cSVOPo->op_sv);
1514+
{
1515+
SV *sv = cSVOPo->op_sv;
1516+
if (!sv) {
1517+
S_opdump_indent(aTHX_ o, level, bar, file,
1518+
"OP_SV = 0x0\n");
13931519
#ifdef USE_ITHREADS
1394-
/* SV is stored in the pad, and the right pad may not be active
1395-
* here, so skip dumping the SV */
1396-
#else
1397-
S_opdump_indent(aTHX_ o, level, bar, file, "SV = %s\n",
1398-
SvPEEK(cSVOP_sv));
1520+
sv = S_get_sv_from_pad(aTHX_ o, o->op_targ);
13991521
#endif
1522+
}
1523+
1524+
if (sv)
1525+
S_opdump_indent(aTHX_ o, level, bar, file,
1526+
"%s = %s (0x%" UVxf ")\n",
1527+
cSVOPo->op_sv ? "OP_SV" : "SV",
1528+
SvPEEK(sv),
1529+
PTR2UV(sv));
1530+
}
14001531
break;
14011532

14021533
case OP_METHOD: /* $obj->$foo */
@@ -1406,19 +1537,40 @@ S_do_op_dump_bar(pTHX_ I32 level, UV bar, PerlIO *file, const OP *o)
14061537
case OP_METHOD_SUPER: /* $obj->SUPER::foo */
14071538
case OP_METHOD_REDIR: /* $obj->BAR::foo */
14081539
case OP_METHOD_REDIR_SUPER: /* $obj->BAR::SUPER::foo */
1409-
#ifndef USE_ITHREADS
1410-
/* with ITHREADS, consts are stored in the pad, and the right pad
1411-
* may not be active here, so skip */
1412-
/* display method name (e.g. 'foo') */
1413-
S_opdump_indent(aTHX_ o, level, bar, file, "SV = %s\n",
1414-
SvPEEK(cMETHOPo_meth));
1540+
{
1541+
/* display method name (e.g. 'foo') */
1542+
SV *sv = cMETHOPo->op_u.op_meth_sv;
1543+
if (!sv) {
1544+
S_opdump_indent(aTHX_ o, level, bar, file,
1545+
"OP_METH_SV = 0x0\n");
1546+
#ifdef USE_ITHREADS
1547+
sv = S_get_sv_from_pad(aTHX_ o, o->op_targ);
1548+
#endif
1549+
}
14151550

1416-
/* display redirect class (e.g. 'BAR') */
1417-
if (optype == OP_METHOD_REDIR || optype == OP_METHOD_REDIR_SUPER) {
1418-
S_opdump_indent(aTHX_ o, level, bar, file, "RCLASS = %s\n",
1419-
SvPEEK(cMETHOPo_rclass));
1420-
}
1551+
if (sv)
1552+
S_opdump_indent(aTHX_ o, level, bar, file,
1553+
"%s = %s (0x%" UVxf ")\n",
1554+
cMETHOPo->op_u.op_meth_sv ? "OP_METH_SV" : "METH",
1555+
SvPEEK(sv),
1556+
PTR2UV(sv));
1557+
1558+
if (optype == OP_METHOD_REDIR || optype == OP_METHOD_REDIR_SUPER) {
1559+
/* display redirect class (e.g. 'BAR') */
1560+
#ifdef USE_ITHREADS
1561+
S_opdump_indent(aTHX_ o, level, bar, file,
1562+
"RCLASS_TARG = %" IVdf "\n", (IV)cMETHOPo->op_rclass_targ);
1563+
sv = S_get_sv_from_pad(aTHX_ o, cMETHOPo->op_rclass_targ);
1564+
#else
1565+
sv = cMETHOPo->op_rclass_sv;
14211566
#endif
1567+
if (sv)
1568+
S_opdump_indent(aTHX_ o, level, bar, file,
1569+
"RCLASS = %s (0x%" UVxf ")\n",
1570+
SvPEEK(sv),
1571+
PTR2UV(sv));
1572+
}
1573+
}
14221574
break;
14231575

14241576
case OP_NULL:

0 commit comments

Comments
 (0)