← Index
NYTProf Performance Profile   « line view »
For ../prof.pl
  Run on Thu Dec 15 15:23:56 2022
Reported on Thu Dec 15 15:27:02 2022

Filename/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/Class/Method/Modifiers.pm
StatementsExecuted 1119 statements in 4.52ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
19222.31ms3.73msClass::Method::Modifiers::::install_modifierClass::Method::Modifiers::install_modifier
47211.39ms1.39msClass::Method::Modifiers::::_sub_attrsClass::Method::Modifiers::_sub_attrs
11128µs30µsMoo::_Utils::::BEGIN@1 Moo::_Utils::BEGIN@1
2229µs493µsClass::Method::Modifiers::::aroundClass::Method::Modifiers::around
1116µs53µsClass::Method::Modifiers::::BEGIN@10Class::Method::Modifiers::BEGIN@10
1116µs11µsClass::Method::Modifiers::::BEGIN@54Class::Method::Modifiers::BEGIN@54
1115µs8µsClass::Method::Modifiers::::BEGIN@145Class::Method::Modifiers::BEGIN@145
1115µs17µsClass::Method::Modifiers::::BEGIN@146Class::Method::Modifiers::BEGIN@146
1115µs8µsClass::Method::Modifiers::::BEGIN@196Class::Method::Modifiers::BEGIN@196
1115µs24µsMoo::_Utils::::BEGIN@2.27 Moo::_Utils::BEGIN@2.27
1113µs8µsClass::Method::Modifiers::::BEGIN@147Class::Method::Modifiers::BEGIN@147
1113µs3µsClass::Method::Modifiers::::BEGIN@19Class::Method::Modifiers::BEGIN@19
1113µs13µsClass::Method::Modifiers::::BEGIN@200Class::Method::Modifiers::BEGIN@200
0000s0sClass::Method::Modifiers::::_freshClass::Method::Modifiers::_fresh
0000s0sClass::Method::Modifiers::::_is_in_packageClass::Method::Modifiers::_is_in_package
0000s0sClass::Method::Modifiers::::afterClass::Method::Modifiers::after
0000s0sClass::Method::Modifiers::::beforeClass::Method::Modifiers::before
0000s0sClass::Method::Modifiers::::freshClass::Method::Modifiers::fresh
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1241µs232µs
# spent 30µs (28+2) within Moo::_Utils::BEGIN@1 which was called: # once (28µs+2µs) by Moo::_Utils::_install_modifier at line 1
use strict;
# spent 30µs making 1 call to Moo::_Utils::BEGIN@1 # spent 2µs making 1 call to strict::import
2233µs243µs
# spent 24µs (5+19) within Moo::_Utils::BEGIN@2.27 which was called: # once (5µs+19µs) by Moo::_Utils::_install_modifier at line 2
use warnings;
# spent 24µs making 1 call to Moo::_Utils::BEGIN@2.27 # spent 19µs making 1 call to warnings::import
3package Class::Method::Modifiers; # git description: v2.12-17-gbc38636
4# ABSTRACT: Provides Moose-like method modifiers
5# KEYWORDS: method wrap modification patch
6# vim: set ts=8 sts=4 sw=4 tw=115 et :
7
811µsour $VERSION = '2.13';
9
10268µs2100µs
# spent 53µs (6+47) within Class::Method::Modifiers::BEGIN@10 which was called: # once (6µs+47µs) by Moo::_Utils::_install_modifier at line 10
use base 'Exporter';
# spent 53µs making 1 call to Class::Method::Modifiers::BEGIN@10 # spent 47µs making 1 call to base::import
11
1211µsour @EXPORT = qw(before after around);
1311µsour @EXPORT_OK = (@EXPORT, qw(fresh install_modifier));
1411µsour %EXPORT_TAGS = (
15 moose => [qw(before after around)],
16 all => \@EXPORT_OK,
17);
18
19
# spent 3µs within Class::Method::Modifiers::BEGIN@19 which was called: # once (3µs+0s) by Moo::_Utils::_install_modifier at line 21
BEGIN {
2013µs *_HAS_READONLY = $] >= 5.008 ? sub(){1} : sub(){0};
211103µs13µs}
# spent 3µs making 1 call to Class::Method::Modifiers::BEGIN@19
22
23our %MODIFIER_CACHE;
24
25# for backward compatibility
26sub _install_modifier; # -w
2711µs*_install_modifier = \&install_modifier;
28
29
# spent 3.73ms (2.31+1.42) within Class::Method::Modifiers::install_modifier which was called 19 times, avg 197µs/call: # 17 times (2.03ms+1.22ms) by Moo::_Utils::_install_modifier at line 86 of Moo/_Utils.pm, avg 191µs/call # 2 times (278µs+206µs) by Class::Method::Modifiers::around at line 162, avg 242µs/call
sub install_modifier {
30199µs my $into = shift;
31196µs my $type = shift;
32197µs my $code = pop;
33198µs my @names = @_;
34
351913µs @names = @{ $names[0] } if ref($names[0]) eq 'ARRAY';
36
37197µs return _fresh($into, $code, @names) if $type eq 'fresh';
38
391950µs for my $name (@names) {
4035121µs3531µs my $hit = $into->can($name) or do {
# spent 31µs making 35 calls to UNIVERSAL::can, avg 886ns/call
41 require Carp;
42 Carp::confess("The method '$name' is not found in the inheritance hierarchy for class $into");
43 };
44
453515µs my $qualified = $into.'::'.$name;
4635110µs my $cache = $MODIFIER_CACHE{$into}{$name} ||= {
47 before => [],
48 after => [],
49 around => [],
50 };
51
52 # this must be the first modifier we're installing
533512µs if (!exists($cache->{"orig"})) {
542156µs216µs
# spent 11µs (6+5) within Class::Method::Modifiers::BEGIN@54 which was called: # once (6µs+5µs) by Moo::_Utils::_install_modifier at line 54
no strict 'refs';
# spent 11µs making 1 call to Class::Method::Modifiers::BEGIN@54 # spent 5µs making 1 call to strict::unimport
55
56 # grab the original method (or undef if the method is inherited)
573534µs $cache->{"orig"} = *{$qualified}{CODE};
58
59 # the "innermost" method, the one that "around" will ultimately wrap
603514µs $cache->{"wrapped"} = $cache->{"orig"} || $hit; #sub {
61 # # we can't cache this, because new methods or modifiers may be
62 # # added between now and when this method is called
63 # for my $package (@{ mro::get_linear_isa($into) }) {
64 # next if $package eq $into;
65 # my $code = *{$package.'::'.$name}{CODE};
66 # goto $code if $code;
67 # }
68 # require Carp;
69 # Carp::confess("$qualified\::$name disappeared?");
70 #};
71 }
72
73 # keep these lists in the order the modifiers are called
743521µs if ($type eq 'after') {
75 push @{ $cache->{$type} }, $code;
76 }
77 else {
783516µs unshift @{ $cache->{$type} }, $code;
79 }
80
81 # wrap the method with another layer of around. much simpler than
82 # the Moose equivalent. :)
833515µs if ($type eq 'around') {
84125µs my $method = $cache->{wrapped};
851226µs12397µs my $attrs = _sub_attrs($code);
# spent 397µs making 12 calls to Class::Method::Modifiers::_sub_attrs, avg 33µs/call
86 # a bare "sub :lvalue {...}" will be parsed as a label and an
87 # indirect method call. force it to be treated as an expression
88 # using +
8912354µs $cache->{wrapped} = eval "package $into; +sub $attrs { \$code->(\$method, \@_); };";
# spent 200ms executing statements in 3 string evals (merged)
# includes 201ms spent executing 75138 calls to 1 sub defined therein. # spent 698µs executing statements in 2 string evals (merged)
# includes 233µs spent executing 88 calls to 1 sub defined therein. # spent 97µs executing statements in string eval
# includes 119µs spent executing 22 calls to 1 sub defined therein. # spent 59µs executing statements in 3 string evals (merged)
# includes 58µs spent executing 16 calls to 1 sub defined therein. # spent 9µs executing statements in string eval
# includes 6µs spent executing 1 call to 1 sub defined therein. # spent 3µs executing statements in string eval # spent 2µs executing statements in string eval
90 }
91
92 # install our new method which dispatches the modifiers, but only
93 # if a new type was added
943534µs if (@{ $cache->{$type} } == 1) {
95
96 # avoid these hash lookups every method invocation
97355µs my $before = $cache->{"before"};
98358µs my $after = $cache->{"after"};
99
100 # this is a coderef that changes every new "around". so we need
101 # to take a reference to it. better a deref than a hash lookup
102356µs my $wrapped = \$cache->{"wrapped"};
103
1043562µs35995µs my $attrs = _sub_attrs($cache->{wrapped});
# spent 995µs making 35 calls to Class::Method::Modifiers::_sub_attrs, avg 28µs/call
105
106355µs my $generated = "package $into;\n";
1073517µs $generated .= "sub $name $attrs {";
108
109 # before is easy, it doesn't affect the return value(s)
1103511µs if (@$before) {
111 $generated .= '
112 for my $method (@$before) {
113 $method->(@_);
114 }
115 ';
116 }
117
118358µs if (@$after) {
119 $generated .= '
120 my $ret;
121 if (wantarray) {
122 $ret = [$$wrapped->(@_)];
123 '.(_HAS_READONLY ? 'Internals::SvREADONLY(@$ret, 1);' : '').'
124 }
125 elsif (defined wantarray) {
126 $ret = \($$wrapped->(@_));
127 }
128 else {
129 $$wrapped->(@_);
130 }
131
132 for my $method (@$after) {
133 $method->(@_);
134 }
135
136 wantarray ? @$ret : $ret ? $$ret : ();
137 '
138 }
139 else {
140352µs $generated .= '$$wrapped->(@_);';
141 }
142
143353µs $generated .= '}';
144
145219µs211µs
# spent 8µs (5+3) within Class::Method::Modifiers::BEGIN@145 which was called: # once (5µs+3µs) by Moo::_Utils::_install_modifier at line 145
no strict 'refs';
# spent 8µs making 1 call to Class::Method::Modifiers::BEGIN@145 # spent 3µs making 1 call to strict::unimport
146211µs229µs
# spent 17µs (5+12) within Class::Method::Modifiers::BEGIN@146 which was called: # once (5µs+12µs) by Moo::_Utils::_install_modifier at line 146
no warnings 'redefine';
# spent 17µs making 1 call to Class::Method::Modifiers::BEGIN@146 # spent 12µs making 1 call to warnings::unimport
1472190µs213µs
# spent 8µs (3+5) within Class::Method::Modifiers::BEGIN@147 which was called: # once (3µs+5µs) by Moo::_Utils::_install_modifier at line 147
no warnings 'closure';
# spent 8µs making 1 call to Class::Method::Modifiers::BEGIN@147 # spent 5µs making 1 call to warnings::unimport
148351.27ms eval $generated;
# spent 170ms executing statements in string eval
# includes 178ms spent executing 75073 calls to 1 sub defined therein. # spent 271µs executing statements in string eval
# includes 187µs spent executing 65 calls to 1 sub defined therein. # spent 179µs executing statements in string eval
# includes 133µs spent executing 68 calls to 1 sub defined therein. # spent 90µs executing statements in string eval
# includes 112µs spent executing 16 calls to 1 sub defined therein. # spent 85µs executing statements in string eval
# includes 338µs spent executing 58 calls to 1 sub defined therein. # spent 73µs executing statements in string eval
# includes 62µs spent executing 20 calls to 1 sub defined therein. # spent 67µs executing statements in string eval
# includes 795µs spent executing 33 calls to 1 sub defined therein. # spent 46µs executing statements in string eval
# includes 36µs spent executing 5 calls to 1 sub defined therein. # spent 43µs executing statements in string eval
# includes 47µs spent executing 8 calls to 1 sub defined therein. # spent 33µs executing statements in string eval
# includes 30µs spent executing 4 calls to 1 sub defined therein. # spent 27µs executing statements in string eval
# includes 32µs spent executing 6 calls to 1 sub defined therein. # spent 15µs executing statements in string eval
# includes 17µs spent executing 4 calls to 1 sub defined therein. # spent 14µs executing statements in string eval
# includes 13µs spent executing 2 calls to 1 sub defined therein. # spent 9µs executing statements in string eval
# includes 21µs spent executing 2 calls to 1 sub defined therein. # spent 8µs executing statements in string eval
# includes 10µs spent executing 1 call to 1 sub defined therein. # spent 6µs executing statements in string eval
# includes 5µs spent executing 1 call to 1 sub defined therein. # spent 5µs executing statements in string eval
# includes 7µs spent executing 1 call to 1 sub defined therein. # spent 3µs executing statements in string eval
# includes 5µs spent executing 1 call to 1 sub defined therein.
149 };
150 }
151}
152
153sub before {
154 _install_modifier(scalar(caller), 'before', @_);
155}
156
157sub after {
158 _install_modifier(scalar(caller), 'after', @_);
159}
160
161
# spent 493µs (9+484) within Class::Method::Modifiers::around which was called 2 times, avg 246µs/call: # once (4µs+331µs) by Module::Runtime::require_module at line 22 of Data/Perl/Collection/Hash/MooseLike.pm # once (5µs+153µs) by Module::Runtime::require_module at line 20 of Data/Perl/Collection/Array/MooseLike.pm
sub around {
16228µs2484µs _install_modifier(scalar(caller), 'around', @_);
# spent 484µs making 2 calls to Class::Method::Modifiers::install_modifier, avg 242µs/call
163}
164
165sub fresh {
166 my $code = pop;
167 my @names = @_;
168
169 @names = @{ $names[0] } if ref($names[0]) eq 'ARRAY';
170
171 _fresh(scalar(caller), $code, @names);
172}
173
174sub _fresh {
175 my ($into, $code, @names) = @_;
176
177 for my $name (@names) {
178 if ($name !~ /\A [a-zA-Z_] [a-zA-Z0-9_]* \z/xms) {
179 require Carp;
180 Carp::confess("Invalid method name '$name'");
181 }
182 if ($into->can($name)) {
183 require Carp;
184 Carp::confess("Class $into already has a method named '$name'");
185 }
186
187 # We need to make sure that the installed method has its CvNAME in
188 # the appropriate package; otherwise, it would be subject to
189 # deletion if callers use namespace::autoclean. If $code was
190 # compiled in the target package, we can just install it directly;
191 # otherwise, we'll need a different approach. Using Sub::Name would
192 # be fine in all cases, at the cost of introducing a dependency on
193 # an XS-using, non-core module. So instead we'll use string-eval to
194 # create a new subroutine that wraps $code.
195 if (_is_in_package($code, $into)) {
196226µs211µs
# spent 8µs (5+3) within Class::Method::Modifiers::BEGIN@196 which was called: # once (5µs+3µs) by Moo::_Utils::_install_modifier at line 196
no strict 'refs';
# spent 8µs making 1 call to Class::Method::Modifiers::BEGIN@196 # spent 3µs making 1 call to strict::unimport
197 *{"$into\::$name"} = $code;
198 }
199 else {
2002133µs223µs
# spent 13µs (3+10) within Class::Method::Modifiers::BEGIN@200 which was called: # once (3µs+10µs) by Moo::_Utils::_install_modifier at line 200
no warnings 'closure'; # for 5.8.x
# spent 13µs making 1 call to Class::Method::Modifiers::BEGIN@200 # spent 10µs making 1 call to warnings::unimport
201 my $attrs = _sub_attrs($code);
202 eval "package $into; sub $name $attrs { \$code->(\@_) }";
203 }
204 }
205}
206
207
# spent 1.39ms within Class::Method::Modifiers::_sub_attrs which was called 47 times, avg 30µs/call: # 35 times (995µs+0s) by Class::Method::Modifiers::install_modifier at line 104, avg 28µs/call # 12 times (397µs+0s) by Class::Method::Modifiers::install_modifier at line 85, avg 33µs/call
sub _sub_attrs {
2084712µs my ($coderef) = @_;
2094711µs local *_sub = $coderef;
2104759µs local $@;
211 # this assignment will fail to compile if it isn't an lvalue sub. we
212 # never want to actually call the sub though, so we return early.
213471.37ms (eval 'return 1; &_sub = 1') ? ':lvalue' : '';
214}
215
216sub _is_in_package {
217 my ($coderef, $package) = @_;
218 require B;
219 my $cv = B::svref_2object($coderef);
220 return $cv->GV->STASH->NAME eq $package;
221}
222
22314µs1;
224
225__END__