B-Tap
view release on metacpan or search on metacpan
lib/Devel/CodeObserver.pm view on Meta::CPAN
package Devel::CodeObserver;
use strict;
use warnings;
use utf8;
use 5.010_001;
our $VERSION = "0.16";
our @WARNINGS;
use B qw(class ppname);
use B::Tap qw(tap);
use B::Tools qw(op_walk);
use Data::Dumper ();
sub new {
my $class = shift;
my %args = @_==1 ? %{$_[0]} : @_;
bless {%args}, $class;
}
sub null {
my $op = shift;
return class($op) eq "NULL";
}
sub call {
my ($class,$code) = @_;
my $cv = B::svref_2object($code);
my @tap_results;
my $root = $cv->ROOT;
# local $B::overlay = {};
if (not null $root) {
op_walk {
if (need_hook($_)) {
my @buf = ($_);
tap($_, $cv->ROOT, \@buf);
push @tap_results, \@buf;
}
} $cv->ROOT;
}
if (0) {
require B::Concise;
my $walker = B::Concise::compile('', '', $code);
$walker->();
}
my $retval = $code->();
return (
$retval,
Devel::CallTrace::Result->new(
code => $code,
tap_results => [grep { @$_ > 1 } @tap_results],
)
);
}
sub need_hook {
my $op = shift;
return 1 if $op->name eq 'entersub';
return 1 if $op->name eq 'padsv';
return 1 if $op->name eq 'aelem';
return 1 if $op->name eq 'helem';
return 1 if $op->name eq 'null' && ppname($op->targ) eq 'pp_rv2sv';
return 0;
}
package Devel::CallTrace::Result;
use Try::Tiny;
use constant { DEBUG => 0 };
sub new {
my $class = shift;
my %args = @_==1 ? %{$_[0]} : @_;
bless {%args}, $class;
}
sub dump_pairs {
my ($self) = @_;
my $tap_results = $self->{tap_results};
my $code = $self->{code};
# We should load B::Deparse lazily. Because loading B::Deparse is really slow.
# It's really big module.
#
# And so, this module is mainly used for testing. And this part is only required if
# the test case was failed. I make faster the passed test case.
require B::Deparse;
my @pairs;
( run in 0.593 second using v1.01-cache-2.11-cpan-39bf76dae61 )