There are twelve backend modules to the compiler in the Perl core, and many more besides on CPAN. Here we'll briefly examine those which are particularly helpful to internals hackers or particularly interesting.
B::Concise was written quite recently by Stephen McCamant to provide a generic way of getting concise information about the op tree. It is highly customizable, and can be used to emulate B::Terse and B::Debug. (see below)
Here's the basic output from B::Concise:
% perl -MO=Concise -e 'print $a+$b' 1r <@> leave[t1] vKP/REFC ->(end) 1k <0> enter ->1l 1l <;> nextstate(main 7 -e:1) v ->1m 1q <@> print vK ->1r 1m <0> pushmark s ->1n 1p <2> add[t1] sK/2 ->1q - <1> ex-rv2sv sK/1 ->1o 1n <$> gvsv(*a) s ->1o - <1> ex-rv2sv sK/1 ->1p 1o <$> gvsv(*b) s ->1p
Each line consists of five main parts:
a label for this operator (in this case, 1r)
a type signifier (@ is a list operator - think arrays)
the name of the op and its target, if any, plus any other information about it
the flags for this operator. Here, v signifies void context and K shows that this operator has children. The private flags are shown after the slash, and are written out as a longer abbreviation than just one character: REFC shows that this op is refcounted.
finally, the label for the next operator in the tree, if there is one.
Note also that, for instance, ops which have been optimized away to a null are left as "ex-...". The exact meanings of the flags and the op classes are given in the B::Concise documentation:
=head2 OP flags abbreviations v OPf_WANT_VOID Want nothing (void context) s OPf_WANT_SCALAR Want single value (scalar context) l OPf_WANT_LIST Want list of any length (list context) K OPf_KIDS There is a firstborn child. P OPf_PARENS This operator was parenthesized. (Or block needs explicit scope entry.) R OPf_REF Certified reference. (Return container, not containee). M OPf_MOD Will modify (lvalue). S OPf_STACKED Some arg is arriving on the stack. * OPf_SPECIAL Do something weird for this op (see op.h) =head2 OP class abbreviations 0 OP (aka BASEOP) An OP with no children 1 UNOP An OP with one child 2 BINOP An OP with two children | LOGOP A control branch OP @ LISTOP An OP that could have lots of children / PMOP An OP with a regular expression $ SVOP An OP with an SV " PVOP An OP with a string { LOOP An OP that holds pointers for a loop ; COP An OP that marks the start of a statement
As with many of the debugging B:: modules, you can use the -exec flag to walk the op tree in execution order, following the chain of op_next's from the start of the tree:
% perl -MO=Concise,-exec -e 'print $a+$b' 1k <0> enter 1l <;> nextstate(main 7 -e:1) v 1m <0> pushmark s 1n <$> gvsv(*a) s 1o <$> gvsv(*b) s 1p <2> add[t1] sK/2 1q <@> print vK 1r <@> leave[t1] vKP/REFC -e syntax OK
Amongst other options, (again, see the documentation) B::Concise supports a -tree option for tree-like ASCII art graphs, and the curious but fun -linenoise option.
B::Debug dumps out all of the information in the op tree; for anything bigger than a trivial program, this is just way too much information. Hence, to sensibly make use of it, it's a good idea to go through with B::Terse or B::Concise first, and find which ops you're interested in, and then grep for them.
Some output from B::Debug looks like this:
LISTOP (0x81121a8) op_next 0x0 op_sibling 0x0 op_ppaddr PL_ppaddr[OP_LEAVE] op_targ 1 op_type 178 op_seq 6433 op_flags 13 op_private 64 op_first 0x81121d0 op_last 0x8190498 op_children 3 OP (0x81121d0) op_next 0x81904c0 op_sibling 0x81904c0 op_ppaddr PL_ppaddr[OP_ENTER] op_targ 0 op_type 177 op_seq 6426 op_flags 0 op_private 0As you should know from the ops chapter, this is all the information contained in the op structure: the type of op and its address, the ops related to it, the C function pointer implementing the PP function, the target on the scratchpad this op uses, its type, sequence number, and public and private flags. It also does similar dumps for SVs. You may find the B::Flags module useful for "Englishifying" the flags.
B::Deparse takes a Perl program and turns it into a Perl program. This doesn't sound very impressive, but it actually does so by decompiling the op tree back into Perl. While this has interesting uses for things like serializing subroutines, it's interesting for internals hackers because it shows us how Perl understands certain constructs. For instance, we can see that logical operators and binary "if" are equivalent:
% perl -MO=Deparse -e '$a and do {$b}' if ($a) { do { $b; }; } -e syntax OKWe can also see, for instance, how the magic that is added by command line switches goes into the op tree:
% perl -MO=Deparse -ane 'print' LINE: while (defined($_ = <ARGV>)) { @F = split(" ", $_, 0); print $_; } -e syntax OK