1
# forked version of B::Utils; needs to merge it ASAP
7
our @EXPORT_OK = qw(all_starts all_roots anon_subs
8
walkoptree_simple walkoptree_filtered
9
walkallops_simple walkallops_filtered
14
my $pack = __PACKAGE__; shift;
17
my %EOK = map {$_ => 1} @EXPORT_OK;
21
Carp::croak(qq{"$_" is not exported by the $pack module});
24
*{"$caller\::$_"} = \&{"$pack\::$_"};
28
our $VERSION = '0.04_02'; # 0.04 with some Schwern patches
30
use B qw(main_start main_root walksymtable class OPf_KIDS);
32
my (%starts, %roots, @anon_subs);
34
our @bad_stashes = qw(B Carp DB Exporter warnings Cwd Config CORE blib strict DynaLoader vars XSLoader AutoLoader base);
38
class( $op ) eq 'NULL';
42
sub _init { # To ensure runtimeness.
44
%starts = ( '__MAIN__' => main_start() );
45
%roots = ( '__MAIN__' => main_root() );
46
walksymtable(\%main::,
49
return if scalar grep {$_[0] eq $_."::"} @bad_stashes;
51
}, # Do not eat our own children!
53
push @anon_subs, { root => $_->ROOT, start => $_->START}
54
for grep { class($_) eq "CV" } B::main_cv->PADLIST->ARRAY->ARRAY;
61
B::Utils - Helper functions for op tree manipulation
69
These functions make it easier to manipulate the op tree.
79
Returns a hash of all of the starting ops or root ops of optrees, keyed
80
to subroutine name; the optree for main program is simply keyed to C<__MAIN__>.
82
B<Note>: Certain "dangerous" stashes are not scanned for subroutines:
83
the list of such stashes can be found in C<@B::Utils::bad_stashes>. Feel
84
free to examine and/or modify this to suit your needs. The intention is
85
that a simple program which uses no modules other than C<B> and
86
C<B::Utils> would show no addition symbols.
88
This does B<not> return the details of ops in anonymous subroutines
89
compiled at compile time. For instance, given
93
the subroutine will not appear in the hash. This is just as well, since
94
they're anonymous... If you want to get at them, use...
98
This returns an array of hash references. Each element has the keys
99
"start" and "root". These are the starting and root ops of all of
100
the anonymous subroutines in the program.
104
sub all_starts { _init(); return %starts; }
105
sub all_roots { _init(); return %roots; }
106
sub anon_subs { _init(); return @anon_subs }
108
sub B::GV::_push_starts {
109
my $name = $_[0]->STASH->NAME."::".$_[0]->SAFENAME;
110
return unless ${$_[0]->CV};
113
if ($cv->PADLIST->can("ARRAY") and $cv->PADLIST->ARRAY and $cv->PADLIST->ARRAY->can("ARRAY")) {
114
push @anon_subs, { root => $_->ROOT, start => $_->START}
115
for grep { class($_) eq "CV" } $cv->PADLIST->ARRAY->ARRAY;
117
return unless ${$cv->START} and ${$cv->ROOT};
118
$starts{$name} = $cv->START;
119
$roots{$name} = $cv->ROOT;
122
sub B::SPECIAL::_push_starts{}
124
=item C<< $op->oldname >>
126
Returns the name of the op, even if it is currently optimized to null.
127
This helps you understand the stucture of the op tree.
132
return substr(B::ppname($_[0]->targ),3) if $_[0]->name eq "null" and $_[0]->targ;
136
=item C<< $op->kids >>
138
Returns an array of all this op's non-null children, in order.
146
foreach my $type (qw(first last other)) {
147
my $kid = $op->$type();
148
next if !$kid || class($kid) eq 'NULL';
149
if( $kid->name eq 'null' ) {
150
push @rv, $kid->kids;
158
foreach my $more_op (@rv) {
159
my $next_op = $more_op;
160
while( $next_op->can("sibling") ) {
161
$next_op = $next_op->sibling;
162
last if !$next_op || class($next_op) eq 'NULL';
163
if( $next_op->name eq 'null' ) {
164
push @more_rv, $next_op->kids;
167
push @more_rv, $next_op;
172
return @rv, @more_rv;
175
=item C<< $op->first >>
177
=item C<< $op->last >>
179
=item C<< $op->other >>
181
Normally if you call first, last or other on anything which is not an
182
UNOP, BINOP or LOGOP respectivly it will die. This leads to lots of
185
$op->first if $op->can('first');
187
B::Utils provides every op with first, last and other methods which
188
will simply return nothing if it isn't relevent.
192
foreach my $type (qw(first last other)) {
194
*{'B::OP::'.$type} = sub {
196
if( $op->can("SUPER::$type") ) {
205
=item C<< $op->parent >>
207
Returns the parent node in the op tree, if possible. Currently "possible" means
208
"if the tree has already been optimized"; that is, if we're during a C<CHECK>
209
block. (and hence, if we have valid C<next> pointers.)
211
In the future, it may be possible to search for the parent before we have the
212
C<next> pointers in place, but it'll take me a while to figure out how to do
219
printf( "parent %s %s=(0x%07x)\n",
225
die "I'm not sure how to do this yet. I'm sure there is a way. If you know, please email me."
228
my (%deadend, $search_kids);
230
my $node = shift || return undef;
232
printf( "Searching from %s %s=(0x%07x)\n",
238
# Go up a level if we've got stuck, and search (for the same
239
# $target) from a higher vantage point.
240
return $search->($node->parent) if exists $deadend{$node};
242
# Test the immediate children
243
return $node if scalar grep {$_ == $target} $node->kids;
247
defined($x = $search->($_)) and return $x for $node->kids;
249
# Not in this subtree.
255
$result = $search->($start) and return $result while $start = $start->next;
256
return $search->($start);
259
=item C<< $op->previous >>
261
Like C<< $op->next >>, but not quite.
265
sub B::OP::previous {
268
my (%deadend, $search);
270
my $node = shift || die;
271
return $search->(find_parent($node)) if exists $deadend{$node};
272
return $node if $node->{next}==$target;
275
($_->next == $target and return $_) for $node->kids;
276
defined($x = $search->($_)) and return $x for $node->{kids};
278
# Not in this subtree.
283
$result = $search->($start) and return $result
284
while $start = $start->next;
287
=item walkoptree_simple($op, \&callback, [$data])
289
The C<B> module provides various functions to walk the op tree, but
290
they're all rather difficult to use, requiring you to inject methods
291
into the C<B::OP> class. This is a very simple op tree walker with
292
more expected semantics.
294
The &callback is called at each op with the op itself passed in as the
295
first argument and any additional $data as the second.
297
All the C<walk> functions set C<$B::Utils::file> and C<$B::Utils::line>
298
to the appropriate values of file and line number in the program
299
being examined. Since only COPs contain this information it may be
300
unavailable in the first few callback calls.
306
# Make sure we reset $file and $line between runs.
307
sub walkoptree_simple {
308
($file, $line) = ('__none__', 0);
310
_walkoptree_simple(@_);
313
sub _walkoptree_simple {
314
my ($op, $callback, $data) = @_;
315
($file, $line) = ($op->file, $op->line) if $op->isa("B::COP");
316
$callback->($op,$data);
317
if ($$op && ($op->flags & OPf_KIDS)) {
319
for ($kid = $op->first; $$kid; $kid = $kid->sibling) {
320
_walkoptree_simple($kid, $callback, $data);
325
=item walkoptree_filtered($op, \&filter, \&callback, [$data])
327
This is much the same as C<walkoptree_simple>, but will only call the
328
callback if the C<filter> returns true. The C<filter> is passed the
329
op in question as a parameter; the C<opgrep> function is fantastic
330
for building your own filters.
334
sub walkoptree_filtered {
335
($file, $line) = ('__none__', 0);
337
_walkoptree_filtered(@_);
340
sub _walkoptree_filtered {
341
my ($op, $filter, $callback, $data) = @_;
342
($file, $line) = ($op->file, $op->line) if $op->isa("B::COP");
343
$callback->($op,$data) if $filter->($op);
344
if ($$op && ($op->flags & OPf_KIDS)) {
346
for ($kid = $op->first; $$kid; $kid = $kid->sibling) {
347
_walkoptree_filtered($kid, $filter, $callback, $data);
352
=item walkallops_simple(\&callback, [$data])
354
This combines C<walkoptree_simple> with C<all_roots> and C<anon_subs>
355
to examine every op in the program. C<$B::Utils::sub> is set to the
356
subroutine name if you're in a subroutine, C<__MAIN__> if you're in
357
the main program and C<__ANON__> if you're in an anonymous subroutine.
363
sub walkallops_simple {
364
my ($callback, $data) = @_;
366
for $sub (keys %roots) {
367
walkoptree_simple($roots{$sub}, $callback, $data);
371
walkoptree_simple($_->{root}, $callback, $data);
375
=item walkallops_filtered(\&filter, \&callback, [$data])
377
Same as above, but filtered.
381
sub walkallops_filtered {
382
my ($filter, $callback, $data) = @_;
384
for $sub (keys %roots) {
385
walkoptree_filtered($roots{$sub}, $filter, $callback, $data);
389
walkoptree_filtered($_->{root}, $filter, $callback, $data);
397
Warn and die, respectively, from the perspective of the position of the op in
398
the program. Sounds complicated, but it's exactly the kind of error reporting
399
you expect when you're grovelling through an op tree.
404
my $args = join '', @_;
405
$args = "Something's wrong " unless $args;
406
$args .= " at $file line $line.\n" unless substr($args, length($args) -1) eq "\n";
409
sub carp (@) { CORE::warn(_preparewarn(@_)) }
410
sub croak (@) { CORE::die(_preparewarn(@_)) }
412
=item opgrep(\%conditions, @ops)
414
Returns the ops which meet the given conditions. The conditions should be
418
{ name => "const", private => OPpCONST_BARE },
422
You can specify alternation by giving an arrayref of values:
424
@svs = opgrep ( { name => ["padsv", "gvsv"] }, @ops)
426
And you can specify inversion by making the first element of the arrayref
427
a "!". (Hint: if you want to say "anything", say "not nothing": C<["!"]>)
429
You may also specify the conditions to be matched in nearby ops.
432
sub { opgrep( {name => "exec",
435
sibling => { name => [qw(! exit warn die)] }
439
carp("Statement unlikely to be reached");
440
carp("\t(Maybe you meant system() when you said exec()?)\n");
446
Here are the things that can be tested:
448
name targ type seq flags private pmflags pmpermflags
449
first other last sibling next pmreplroot pmreplstart pmnext
454
my ($cref, @ops) = @_;
458
OPLOOP: for my $o (grep defined, @ops) {
459
# First, let's skim off ops of the wrong type.
460
for my $type (qw(first other last pmreplroot pmreplstart pmnext pmflags pmpermflags)) {
461
next OPLOOP if exists $conds{$type} and !$o->can($type);
464
for my $test (qw(name targ type seq flags private pmflags pmpermflags)) {
465
next unless exists $conds{$test};
466
next OPLOOP unless $o->can($test);
468
my @conds = ref $conds{$test} ? @{$conds{$test}} : $conds{$test};
470
if ($conds[0] eq "!") {
471
my @conds = @{$conds{$test}}; shift @conds;
472
next OPLOOP if grep {$o->$test eq $_} @conds;
474
next OPLOOP unless grep {$o->$test eq $_} @conds;
478
for my $neighbour (qw(first other last sibling next pmreplroot pmreplstart pmnext)) {
479
next unless exists $conds{$neighbour};
480
# We know it can, because we tested that above
482
next OPLOOP unless opgrep($conds{$neighbour}, $o->$neighbour);
504
Simon Cozens, C<simon@cpan.org>
508
I need to add more Fun Things, and possibly clean up some parts where
509
the (previous/parent) algorithm has catastrophic cases, but it's more
510
important to get this out right now than get it right.
514
L<B>, L<B::Generate>.