← Index
NYTProf Performance Profile   « line view »
For ../prof.pl
  Run on Wed Dec 14 16:10:05 2022
Reported on Wed Dec 14 16:12:57 2022

Filename/Users/ether/.perlbrew/libs/36.0@std/lib/perl5/Class/Method/Modifiers.pm
StatementsExecuted 1119 statements in 7.08ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
19223.66ms5.87msClass::Method::Modifiers::::install_modifierClass::Method::Modifiers::install_modifier
47212.16ms2.16msClass::Method::Modifiers::::_sub_attrsClass::Method::Modifiers::_sub_attrs
11148µs53µsMoo::_Utils::::BEGIN@1 Moo::_Utils::BEGIN@1
22214µs1.04msClass::Method::Modifiers::::aroundClass::Method::Modifiers::around
11112µs86µsClass::Method::Modifiers::::BEGIN@10Class::Method::Modifiers::BEGIN@10
11110µs55µsMoo::_Utils::::BEGIN@2.27 Moo::_Utils::BEGIN@2.27
1119µs13µsClass::Method::Modifiers::::BEGIN@196Class::Method::Modifiers::BEGIN@196
1118µs18µsClass::Method::Modifiers::::BEGIN@54Class::Method::Modifiers::BEGIN@54
1117µs11µsClass::Method::Modifiers::::BEGIN@145Class::Method::Modifiers::BEGIN@145
1116µs25µsClass::Method::Modifiers::::BEGIN@146Class::Method::Modifiers::BEGIN@146
1116µs14µsClass::Method::Modifiers::::BEGIN@147Class::Method::Modifiers::BEGIN@147
1116µs18µsClass::Method::Modifiers::::BEGIN@200Class::Method::Modifiers::BEGIN@200
1115µs5µsClass::Method::Modifiers::::BEGIN@19Class::Method::Modifiers::BEGIN@19
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
1251µs258µs
# spent 53µs (48+5) within Moo::_Utils::BEGIN@1 which was called: # once (48µs+5µs) by Moo::_Utils::_install_modifier at line 1
use strict;
# spent 53µs making 1 call to Moo::_Utils::BEGIN@1 # spent 5µs making 1 call to strict::import
2256µs2100µs
# spent 55µs (10+45) within Moo::_Utils::BEGIN@2.27 which was called: # once (10µs+45µs) by Moo::_Utils::_install_modifier at line 2
use warnings;
# spent 55µs making 1 call to Moo::_Utils::BEGIN@2.27 # spent 45µ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
810sour $VERSION = '2.13';
9
102108µs2160µs
# spent 86µs (12+74) within Class::Method::Modifiers::BEGIN@10 which was called: # once (12µs+74µs) by Moo::_Utils::_install_modifier at line 10
use base 'Exporter';
# spent 86µs making 1 call to Class::Method::Modifiers::BEGIN@10 # spent 74µs making 1 call to base::import
11
1211µsour @EXPORT = qw(before after around);
1310sour @EXPORT_OK = (@EXPORT, qw(fresh install_modifier));
1413µsour %EXPORT_TAGS = (
15 moose => [qw(before after around)],
16 all => \@EXPORT_OK,
17);
18
19
# spent 5µs within Class::Method::Modifiers::BEGIN@19 which was called: # once (5µs+0s) by Moo::_Utils::_install_modifier at line 21
BEGIN {
2015µs *_HAS_READONLY = $] >= 5.008 ? sub(){1} : sub(){0};
211185µs15µs}
# spent 5µs making 1 call to Class::Method::Modifiers::BEGIN@19
22
23our %MODIFIER_CACHE;
24
25# for backward compatibility
26sub _install_modifier; # -w
2712µs*_install_modifier = \&install_modifier;
28
29
# spent 5.87ms (3.66+2.21) within Class::Method::Modifiers::install_modifier which was called 19 times, avg 309µs/call: # 17 times (3.15ms+1.69ms) by Moo::_Utils::_install_modifier at line 86 of Moo/_Utils.pm, avg 285µs/call # 2 times (513µs+514µs) by Class::Method::Modifiers::around at line 162, avg 514µs/call
sub install_modifier {
30198µs my $into = shift;
311911µs my $type = shift;
32199µs my $code = pop;
33197µs my @names = @_;
34
351915µs @names = @{ $names[0] } if ref($names[0]) eq 'ARRAY';
36
37196µs return _fresh($into, $code, @names) if $type eq 'fresh';
38
391973µs for my $name (@names) {
4035204µs3543µs my $hit = $into->can($name) or do {
# spent 43µs making 35 calls to UNIVERSAL::can, avg 1µs/call
41 require Carp;
42 Carp::confess("The method '$name' is not found in the inheritance hierarchy for class $into");
43 };
44
453521µs my $qualified = $into.'::'.$name;
463587µ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
533517µs if (!exists($cache->{"orig"})) {
542220µs228µs
# spent 18µs (8+10) within Class::Method::Modifiers::BEGIN@54 which was called: # once (8µs+10µs) by Moo::_Utils::_install_modifier at line 54
no strict 'refs';
# spent 18µs making 1 call to Class::Method::Modifiers::BEGIN@54 # spent 10µs making 1 call to strict::unimport
55
56 # grab the original method (or undef if the method is inherited)
573565µs $cache->{"orig"} = *{$qualified}{CODE};
58
59 # the "innermost" method, the one that "around" will ultimately wrap
603515µ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 {
783525µs unshift @{ $cache->{$type} }, $code;
79 }
80
81 # wrap the method with another layer of around. much simpler than
82 # the Moose equivalent. :)
833516µs if ($type eq 'around') {
84127µs my $method = $cache->{wrapped};
851228µs12585µs my $attrs = _sub_attrs($code);
# spent 585µs making 12 calls to Class::Method::Modifiers::_sub_attrs, avg 49µ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 +
8912639µs $cache->{wrapped} = eval "package $into; +sub $attrs { \$code->(\$method, \@_); };";
# spent 265ms executing statements in 3 string evals (merged)
# includes 263ms spent executing 73713 calls to 1 sub defined therein. # spent 298µs executing statements in 2 string evals (merged)
# includes 324µs spent executing 88 calls to 1 sub defined therein. # spent 113µs executing statements in string eval
# includes 129µs spent executing 22 calls to 1 sub defined therein. # spent 66µs executing statements in 3 string evals (merged)
# includes 146µs spent executing 16 calls to 1 sub defined therein. # spent 9µs executing statements in string eval
# includes 7µs spent executing 1 call to 1 sub defined therein. # spent 5µs executing statements in string eval # spent 3µ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
943551µs if (@{ $cache->{$type} } == 1) {
95
96 # avoid these hash lookups every method invocation
97358µs my $before = $cache->{"before"};
98355µ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
1023511µs my $wrapped = \$cache->{"wrapped"};
103
10435102µs351.58ms my $attrs = _sub_attrs($cache->{wrapped});
# spent 1.58ms making 35 calls to Class::Method::Modifiers::_sub_attrs, avg 45µs/call
105
1063517µs my $generated = "package $into;\n";
1073513µs $generated .= "sub $name $attrs {";
108
109 # before is easy, it doesn't affect the return value(s)
1103522µs if (@$before) {
111 $generated .= '
112 for my $method (@$before) {
113 $method->(@_);
114 }
115 ';
116 }
117
1183516µ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 {
1403566µs $generated .= '$$wrapped->(@_);';
141 }
142
143354µs $generated .= '}';
144
145229µs215µs
# spent 11µs (7+4) within Class::Method::Modifiers::BEGIN@145 which was called: # once (7µs+4µs) by Moo::_Utils::_install_modifier at line 145
no strict 'refs';
# spent 11µs making 1 call to Class::Method::Modifiers::BEGIN@145 # spent 4µs making 1 call to strict::unimport
146219µs244µs
# spent 25µs (6+19) within Class::Method::Modifiers::BEGIN@146 which was called: # once (6µs+19µs) by Moo::_Utils::_install_modifier at line 146
no warnings 'redefine';
# spent 25µs making 1 call to Class::Method::Modifiers::BEGIN@146 # spent 19µs making 1 call to warnings::unimport
1472308µs222µs
# spent 14µs (6+8) within Class::Method::Modifiers::BEGIN@147 which was called: # once (6µs+8µs) by Moo::_Utils::_install_modifier at line 147
no warnings 'closure';
# spent 14µs making 1 call to Class::Method::Modifiers::BEGIN@147 # spent 8µs making 1 call to warnings::unimport
148351.98ms eval $generated;
# spent 233ms executing statements in string eval
# includes 238ms spent executing 73648 calls to 1 sub defined therein. # spent 263µs executing statements in string eval
# includes 170µs spent executing 65 calls to 1 sub defined therein. # spent 214µs executing statements in string eval
# includes 245µs spent executing 68 calls to 1 sub defined therein. # spent 210µs executing statements in string eval
# includes 173µs spent executing 16 calls to 1 sub defined therein. # spent 81µs executing statements in string eval
# includes 69µs spent executing 20 calls to 1 sub defined therein. # spent 77µs executing statements in string eval
# includes 165µs spent executing 33 calls to 1 sub defined therein. # spent 76µs executing statements in string eval
# includes 342µs spent executing 58 calls to 1 sub defined therein. # spent 68µs executing statements in string eval
# includes 91µs spent executing 8 calls to 1 sub defined therein. # spent 54µs executing statements in string eval
# includes 65µs spent executing 6 calls to 1 sub defined therein. # spent 38µs executing statements in string eval
# includes 47µs spent executing 5 calls to 1 sub defined therein. # spent 37µs executing statements in string eval
# includes 48µs spent executing 4 calls to 1 sub defined therein. # spent 20µs executing statements in string eval
# includes 14µs spent executing 2 calls to 1 sub defined therein. # spent 17µs executing statements in string eval
# includes 20µs spent executing 4 calls to 1 sub defined therein. # spent 12µs executing statements in string eval
# includes 30µs spent executing 2 calls to 1 sub defined therein. # spent 12µs executing statements in string eval
# includes 13µs spent executing 1 call to 1 sub defined therein. # spent 10µs executing statements in string eval
# includes 11µs spent executing 1 call to 1 sub defined therein. # spent 5µs executing statements in string eval
# includes 5µs spent executing 1 call to 1 sub defined therein. # spent 4µs executing statements in string eval
# includes 4µs spent executing 1 call to 1 sub defined therein. # spent 0s executing statements in string eval
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 1.04ms (14µs+1.03) within Class::Method::Modifiers::around which was called 2 times, avg 520µs/call: # once (6µs+736µs) by Module::Runtime::require_module at line 22 of Data/Perl/Collection/Hash/MooseLike.pm # once (8µs+291µs) by Module::Runtime::require_module at line 20 of Data/Perl/Collection/Array/MooseLike.pm
sub around {
162213µs21.03ms _install_modifier(scalar(caller), 'around', @_);
# spent 1.03ms making 2 calls to Class::Method::Modifiers::install_modifier, avg 514µ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)) {
196239µs217µs
# spent 13µs (9+4) within Class::Method::Modifiers::BEGIN@196 which was called: # once (9µs+4µs) by Moo::_Utils::_install_modifier at line 196
no strict 'refs';
# spent 13µs making 1 call to Class::Method::Modifiers::BEGIN@196 # spent 4µs making 1 call to strict::unimport
197 *{"$into\::$name"} = $code;
198 }
199 else {
2002216µs230µs
# spent 18µs (6+12) within Class::Method::Modifiers::BEGIN@200 which was called: # once (6µs+12µs) by Moo::_Utils::_install_modifier at line 200
no warnings 'closure'; # for 5.8.x
# spent 18µs making 1 call to Class::Method::Modifiers::BEGIN@200 # spent 12µ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 2.16ms within Class::Method::Modifiers::_sub_attrs which was called 47 times, avg 46µs/call: # 35 times (1.58ms+0s) by Class::Method::Modifiers::install_modifier at line 104, avg 45µs/call # 12 times (585µs+0s) by Class::Method::Modifiers::install_modifier at line 85, avg 49µs/call
sub _sub_attrs {
2084710µs my ($coderef) = @_;
2094738µs local *_sub = $coderef;
210479µ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.
213472.19ms (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
22317µs1;
224
225__END__