B-C
view release on metacpan or search on metacpan
perloptree.pod view on Meta::CPAN
all the closed execution loops of its subcomponents and links
them into a new closed loop for the higher level node. But it's
still not the real execution order.
I<Todo: Sample>
Additional context-dependent optimizations are performed at this
time. Since at this moment the compile tree contains back-references
(via "thread" pointers), nodes cannot be C<free()>d now. To allow
optimized-away nodes at this stage, such nodes are C<null()>ified
instead of C<free()>'ing (i.e. their type is changed to C<OP_NULL>).
=head2 Compile pass 3: peephole optimization
The actual execution order is not known till we get a grammar
reduction to a top-level unit like a subroutine or file that will
be called by "name" rather than via a "next" pointer. At that
point, we can call into peep() to do that code's portion of the
3rd pass. It has to be recursive, but it's recursive on basic
blocks, not on tree nodes.
So finally, when the full parse tree is generated, the "peephole
optimizer" C<peep()> is running. This pass is neither top-down
or bottom-up, but in the execution order with additional
complications for conditionals.
This examines each op in the tree and attempts to determine "local"
optimizations by "thinking ahead" one or two ops and seeing if
multiple operations can be combined into one (by nullifying and
re-ordering the next pointers).
It also checks for lexical issues such as the effect of C<use
strict> on bareword constants. Note that since the last walk the
early sibling pointers for recursive (bottom-up) meta-inspection
are useless, the final exec order is guaranteed by the next and
flags fields.
If write an rpeep extension by your own, beware that the default mode
of peep is to nullify ops.
=head1 basic vs exec order
The highly recursive Yacc parser generates the initial op tree in
B<basic> order. To save memory and run-time the final execution
order of the ops in sequential order is not copied around, just
the next pointers are rehooked in C<Perl_linklist()> to the
so-called B<exec> order. So the exec walk through the
linked-list of ops is not too cache-friendly.
In detail C<Perl_linklist()> traverses the op tree, and sets
op-next pointers to give the execution order for that op
tree. op-sibling pointers are rarely unneeded after that.
Walkers can run in "basic" or "exec" order. "basic" is useful
for the memory layout, it contains the history, "exec" is more
useful to understand the logic and program flow. The
L</B::Bytecode> section has an extensive example about the order.
=head1 OP Structure and Inheritance
The basic C<struct op> looks basically like
C<{ OP* op_next, OP* op_sibling, OP* op_ppaddr, ..., int op_flags, int op_private } OP;>
See L</BASEOP> below.
Each op is defined in size, arguments, return values, class and
more in the F<opcode.pl> table. (See L</"OP Class Declarations in
opcode.pl"> below.)
The class of an OP determines its size and the number of
children. But the number and type of arguments is not so easy to
declare as in C. F<opcode.pl> tries to declare some XS-prototype
like arguments, but in lisp we would say most ops are "special"
functions, context-dependent, with special parsing and precedence rules.
F<B.pm> L<http://search.cpan.org/perldoc?B> contains these
classes and inheritance:
@B::OP::ISA = 'B::OBJECT';
@B::UNOP::ISA = 'B::OP';
@B::BINOP::ISA = 'B::UNOP';
@B::LOGOP::ISA = 'B::UNOP';
@B::LISTOP::ISA = 'B::BINOP';
@B::SVOP::ISA = 'B::OP';
@B::PADOP::ISA = 'B::OP';
@B::PVOP::ISA = 'B::OP';
@B::LOOP::ISA = 'B::LISTOP';
@B::PMOP::ISA = 'B::LISTOP';
@B::COP::ISA = 'B::OP';
@B::SPECIAL::ISA = 'B::OBJECT';
@B::optype = qw(OP UNOP BINOP LOGOP LISTOP PMOP SVOP PADOP PVOP LOOP COP);
I<TODO: ascii graph from perlguts>
F<op.h> L<http://search.cpan.org/src/JESSE/perl-5.12.1/op.h>
contains all the gory details. Let's check it out:
=head2 OP Class Declarations in opcode.pl
The full list of op declarations is defined as C<DATA> in
F<opcode.pl>. It defines the class, the name, some flags, and
the argument types, the so-called "operands". C<make regen> (via
F<regen.pl>) recreates out of this DATA table the files
F<opcode.h>, F<opnames.h>, F<pp_proto.h> and F<pp.sym>.
The class signifiers in F<opcode.pl> are:
baseop - 0 unop - 1 binop - 2
logop - | listop - @ pmop - /
padop/svop - $ padop - # (unused) loop - {
baseop/unop - % loopexop - } filestatop - -
pvop/svop - " cop - ;
Other options within F<opcode.pl> are:
needs stack mark - m
needs constant folding - f
produces a scalar - s
produces an integer - i
needs a target - t
( run in 1.577 second using v1.01-cache-2.11-cpan-99c4e6809bf )