| Filename | /usr/local/share/perl/5.18.2/Sub/Quote.pm |
| Statements | Executed 281 statements in 10.9ms |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 2.82ms | 3.59ms | Sub::Quote::BEGIN@10 |
| 2 | 1 | 1 | 1.66ms | 1.78ms | Sub::Quote::_clean_eval |
| 1 | 1 | 1 | 999µs | 1.31ms | Sub::Quote::BEGIN@7 |
| 82 | 9 | 3 | 300µs | 456µs | Sub::Quote::quotify |
| 2 | 1 | 1 | 163µs | 279µs | Sub::Quote::capture_unroll |
| 2 | 1 | 1 | 161µs | 252µs | Sub::Quote::quote_sub |
| 2 | 1 | 1 | 143µs | 2.22ms | Sub::Quote::unquote_sub |
| 12 | 1 | 1 | 30µs | 30µs | Sub::Quote::quoted_from_sub |
| 18 | 2 | 1 | 28µs | 28µs | Sub::Quote::CORE:match (opcode) |
| 1 | 1 | 1 | 15µs | 47µs | Sub::Quote::BEGIN@5 |
| 2 | 1 | 1 | 12µs | 12µs | Sub::Quote::CORE:subst (opcode) |
| 1 | 1 | 1 | 11µs | 28µs | Sub::Quote::BEGIN@162 |
| 1 | 1 | 1 | 10µs | 40µs | Sub::Quote::BEGIN@8 |
| 1 | 1 | 1 | 9µs | 17µs | Sub::Quote::BEGIN@9 |
| 1 | 1 | 1 | 7µs | 7µs | Sub::Quote::BEGIN@11 |
| 0 | 0 | 0 | 0s | 0s | Sub::Quote::CLONE |
| 0 | 0 | 0 | 0s | 0s | Sub::Quote::__ANON__[:107] |
| 0 | 0 | 0 | 0s | 0s | Sub::Quote::inlinify |
| 0 | 0 | 0 | 0s | 0s | Sub::Quote::qsub |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | package Sub::Quote; | ||||
| 2 | |||||
| 3 | 2 | 470µs | # spent 1.78ms (1.66+119µs) within Sub::Quote::_clean_eval which was called 2 times, avg 892µs/call:
# 2 times (1.66ms+119µs) by Sub::Quote::unquote_sub at line 167, avg 892µs/call # spent 985µs executing statements in string eval # includes 234µs spent executing 5 calls to 3 subs defined therein. # spent 448µs executing statements in string eval # includes 78µs spent executing 5 calls to 3 subs defined therein. | ||
| 4 | |||||
| 5 | 2 | 36µs | 2 | 78µs | # spent 47µs (15+32) within Sub::Quote::BEGIN@5 which was called:
# once (15µs+32µs) by Method::Generate::Constructor::BEGIN@4 at line 5 # spent 47µs making 1 call to Sub::Quote::BEGIN@5
# spent 32µs making 1 call to Moo::_strictures::import |
| 6 | |||||
| 7 | 2 | 117µs | 2 | 1.36ms | # spent 1.31ms (999µs+308µs) within Sub::Quote::BEGIN@7 which was called:
# once (999µs+308µs) by Method::Generate::Constructor::BEGIN@4 at line 7 # spent 1.31ms making 1 call to Sub::Quote::BEGIN@7
# spent 49µs making 1 call to Exporter::import |
| 8 | 2 | 32µs | 2 | 70µs | # spent 40µs (10+30) within Sub::Quote::BEGIN@8 which was called:
# once (10µs+30µs) by Method::Generate::Constructor::BEGIN@4 at line 8 # spent 40µs making 1 call to Sub::Quote::BEGIN@8
# spent 30µs making 1 call to Exporter::import |
| 9 | 2 | 26µs | 2 | 24µs | # spent 17µs (9+7) within Sub::Quote::BEGIN@9 which was called:
# once (9µs+7µs) by Method::Generate::Constructor::BEGIN@4 at line 9 # spent 17µs making 1 call to Sub::Quote::BEGIN@9
# spent 7µs making 1 call to Exporter::import |
| 10 | 2 | 173µs | 1 | 3.59ms | # spent 3.59ms (2.82+770µs) within Sub::Quote::BEGIN@10 which was called:
# once (2.82ms+770µs) by Method::Generate::Constructor::BEGIN@4 at line 10 # spent 3.59ms making 1 call to Sub::Quote::BEGIN@10 |
| 11 | # spent 7µs within Sub::Quote::BEGIN@11 which was called:
# once (7µs+0s) by Method::Generate::Constructor::BEGIN@4 at line 13 | ||||
| 12 | 1 | 7µs | *_HAVE_PERLSTRING = defined &B::perlstring ? sub(){1} : sub(){0}; | ||
| 13 | 1 | 1.24ms | 1 | 7µs | } # spent 7µs making 1 call to Sub::Quote::BEGIN@11 |
| 14 | |||||
| 15 | 1 | 800ns | our $VERSION = '2.001000'; | ||
| 16 | 1 | 21µs | $VERSION = eval $VERSION; # spent 3µs executing statements in string eval | ||
| 17 | |||||
| 18 | 1 | 2µs | our @EXPORT = qw(quote_sub unquote_sub quoted_from_sub qsub); | ||
| 19 | 1 | 800ns | our @EXPORT_OK = qw(quotify capture_unroll inlinify); | ||
| 20 | |||||
| 21 | 1 | 300ns | our %QUOTED; | ||
| 22 | |||||
| 23 | # spent 456µs (300+157) within Sub::Quote::quotify which was called 82 times, avg 6µs/call:
# 16 times (68µs+29µs) by Sub::Quote::capture_unroll at line 36, avg 6µs/call
# 15 times (58µs+23µs) by Method::Generate::Constructor::_assign_new at line 213 of Method/Generate/Constructor.pm, avg 5µs/call
# 15 times (58µs+21µs) by Method::Generate::Accessor::_generate_simple_set at line 543 of Method/Generate/Accessor.pm, avg 5µs/call
# 15 times (42µs+29µs) by Method::Generate::Accessor::_generate_core_set at line 537 of Method/Generate/Accessor.pm, avg 5µs/call
# 9 times (24µs+9µs) by Method::Generate::Accessor::_wrap_attr_exception at line 421 of Method/Generate/Accessor.pm, avg 4µs/call
# 4 times (15µs+20µs) by Sub::Quote::quote_sub at line 88, avg 9µs/call
# 3 times (10µs+4µs) by Method::Generate::Accessor::_attr_desc at line 384 of Method/Generate/Accessor.pm, avg 5µs/call
# 3 times (8µs+6µs) by Method::Generate::Accessor::_wrap_attr_exception at line 420 of Method/Generate/Accessor.pm, avg 5µs/call
# 2 times (16µs+17µs) by Method::Generate::Constructor::_handle_subconstructor at line 161 of Method/Generate/Constructor.pm, avg 16µs/call | ||||
| 24 | 82 | 533µs | 82 | 157µs | ! defined $_[0] ? 'undef()' # spent 157µs making 82 calls to B::perlstring, avg 2µs/call |
| 25 | : _HAVE_PERLSTRING ? B::perlstring($_[0]) | ||||
| 26 | : qq["\Q$_[0]\E"]; | ||||
| 27 | } | ||||
| 28 | |||||
| 29 | # spent 279µs (163+115) within Sub::Quote::capture_unroll which was called 2 times, avg 139µs/call:
# 2 times (163µs+115µs) by Sub::Quote::unquote_sub at line 143, avg 139µs/call | ||||
| 30 | 2 | 2µs | my ($from, $captures, $indent) = @_; | ||
| 31 | 16 | 62µs | 16 | 19µs | join( # spent 19µs making 16 calls to Sub::Quote::CORE:match, avg 1µs/call |
| 32 | '', | ||||
| 33 | map { | ||||
| 34 | 2 | 33µs | /^([\@\%\$])/ | ||
| 35 | or die "capture key should start with \@, \% or \$: $_"; | ||||
| 36 | 32 | 85µs | 16 | 97µs | (' ' x $indent).qq{my ${_} = ${1}{${from}->{${\quotify $_}}};\n}; # spent 97µs making 16 calls to Sub::Quote::quotify, avg 6µs/call |
| 37 | } keys %$captures | ||||
| 38 | ); | ||||
| 39 | } | ||||
| 40 | |||||
| 41 | sub inlinify { | ||||
| 42 | my ($code, $args, $extra, $local) = @_; | ||||
| 43 | my $do = 'do { '.($extra||''); | ||||
| 44 | if ($code =~ s/^(\s*package\s+([a-zA-Z0-9:]+);)//) { | ||||
| 45 | $do .= $1; | ||||
| 46 | } | ||||
| 47 | if ($code =~ s{ | ||||
| 48 | \A((?:\#\ BEGIN\ quote_sub\ PRELUDE\n.*?\#\ END\ quote_sub\ PRELUDE\n)?\s*) | ||||
| 49 | (^\s*) my \s* \(([^)]+)\) \s* = \s* \@_; | ||||
| 50 | }{}xms) { | ||||
| 51 | my ($pre, $indent, $code_args) = ($1, $2, $3); | ||||
| 52 | $do .= $pre; | ||||
| 53 | if ($code_args ne $args) { | ||||
| 54 | $do .= $indent . 'my ('.$code_args.') = ('.$args.'); '; | ||||
| 55 | } | ||||
| 56 | } | ||||
| 57 | elsif ($local || $args ne '@_') { | ||||
| 58 | $do .= ($local ? 'local ' : '').'@_ = ('.$args.'); '; | ||||
| 59 | } | ||||
| 60 | $do.$code.' }'; | ||||
| 61 | } | ||||
| 62 | |||||
| 63 | # spent 252µs (161+91) within Sub::Quote::quote_sub which was called 2 times, avg 126µs/call:
# 2 times (161µs+91µs) by Method::Generate::Constructor::generate_method at line 154 of Method/Generate/Constructor.pm, avg 126µs/call | ||||
| 64 | # HOLY DWIMMERY, BATMAN! | ||||
| 65 | # $name => $code => \%captures => \%options | ||||
| 66 | # $name => $code => \%captures | ||||
| 67 | # $name => $code | ||||
| 68 | # $code => \%captures => \%options | ||||
| 69 | # $code | ||||
| 70 | 2 | 15µs | my $options = | ||
| 71 | (ref($_[-1]) eq 'HASH' and ref($_[-2]) eq 'HASH') | ||||
| 72 | ? pop | ||||
| 73 | : {}; | ||||
| 74 | 2 | 1µs | my $captures = ref($_[-1]) eq 'HASH' ? pop : undef; | ||
| 75 | 2 | 3µs | undef($captures) if $captures && !keys %$captures; | ||
| 76 | 2 | 11µs | my $code = pop; | ||
| 77 | 2 | 1µs | my $name = $_[0]; | ||
| 78 | 2 | 2µs | if ($name) { | ||
| 79 | 2 | 900ns | my $subname = $name; | ||
| 80 | 2 | 29µs | 2 | 12µs | my $package = $subname =~ s/(.*)::// ? $1 : caller; # spent 12µs making 2 calls to Sub::Quote::CORE:subst, avg 6µs/call |
| 81 | 2 | 2µs | $name = join '::', $package, $subname; | ||
| 82 | 2 | 5µs | die "package name $package too long!" | ||
| 83 | if length $package > 252; | ||||
| 84 | 2 | 2µs | die "sub name $subname too long!" | ||
| 85 | if length $subname > 252; | ||||
| 86 | } | ||||
| 87 | 2 | 13µs | my ($package, $hints, $bitmask, $hintshash) = (caller(0))[0,8,9,10]; | ||
| 88 | 2 | 18µs | 4 | 35µs | my $context # spent 35µs making 4 calls to Sub::Quote::quotify, avg 9µs/call |
| 89 | ="# BEGIN quote_sub PRELUDE\n" | ||||
| 90 | ."package $package;\n" | ||||
| 91 | ."BEGIN {\n" | ||||
| 92 | ." \$^H = ".quotify($hints).";\n" | ||||
| 93 | ." \${^WARNING_BITS} = ".quotify($bitmask).";\n" | ||||
| 94 | ." \%^H = (\n" | ||||
| 95 | . join('', map | ||||
| 96 | " ".quotify($_)." => ".quotify($hintshash->{$_}).",", | ||||
| 97 | keys %$hintshash) | ||||
| 98 | ." );\n" | ||||
| 99 | ."}\n" | ||||
| 100 | ."# END quote_sub PRELUDE\n"; | ||||
| 101 | 2 | 10µs | $code = "$context$code"; | ||
| 102 | 2 | 400ns | my $quoted_info; | ||
| 103 | 2 | 500ns | my $unquoted; | ||
| 104 | my $deferred = defer_sub +($options->{no_install} ? undef : $name) => sub { | ||||
| 105 | $unquoted if 0; | ||||
| 106 | unquote_sub($quoted_info->[4]); | ||||
| 107 | 2 | 16µs | 2 | 38µs | }; # spent 38µs making 2 calls to Sub::Defer::defer_sub, avg 19µs/call |
| 108 | 2 | 8µs | $quoted_info = [ $name, $code, $captures, \$unquoted, $deferred ]; | ||
| 109 | 2 | 8µs | 2 | 2µs | weaken($quoted_info->[3]); # spent 2µs making 2 calls to Scalar::Util::weaken, avg 1µs/call |
| 110 | 2 | 6µs | 2 | 2µs | weaken($quoted_info->[4]); # spent 2µs making 2 calls to Scalar::Util::weaken, avg 850ns/call |
| 111 | 2 | 7µs | 2 | 2µs | weaken($QUOTED{$deferred} = $quoted_info); # spent 2µs making 2 calls to Scalar::Util::weaken, avg 850ns/call |
| 112 | 2 | 9µs | return $deferred; | ||
| 113 | } | ||||
| 114 | |||||
| 115 | # spent 30µs within Sub::Quote::quoted_from_sub which was called 12 times, avg 3µs/call:
# 12 times (30µs+0s) by Method::Generate::Accessor::_generate_call_code at line 456 of Method/Generate/Accessor.pm, avg 3µs/call | ||||
| 116 | 12 | 4µs | my ($sub) = @_; | ||
| 117 | 12 | 7.46ms | my $quoted_info = $QUOTED{$sub||''} or return undef; | ||
| 118 | my ($name, $code, $captured, $unquoted, $deferred) = @{$quoted_info}; | ||||
| 119 | $unquoted &&= $$unquoted; | ||||
| 120 | if (($deferred && $deferred eq $sub) | ||||
| 121 | || ($unquoted && $unquoted eq $sub)) { | ||||
| 122 | return [ $name, $code, $captured, $unquoted, $deferred ]; | ||||
| 123 | } | ||||
| 124 | return undef; | ||||
| 125 | } | ||||
| 126 | |||||
| 127 | # spent 2.22ms (143µs+2.08) within Sub::Quote::unquote_sub which was called 2 times, avg 1.11ms/call:
# 2 times (143µs+2.08ms) by Method::Generate::Constructor::__ANON__[/usr/local/share/perl/5.18.2/Method/Generate/Constructor.pm:102] at line 96 of Method/Generate/Constructor.pm, avg 1.11ms/call | ||||
| 128 | 2 | 1µs | my ($sub) = @_; | ||
| 129 | 2 | 2µs | my $quoted = $QUOTED{$sub} or return undef; | ||
| 130 | 2 | 2µs | my $unquoted = $quoted->[3]; | ||
| 131 | 2 | 2µs | unless ($unquoted && $$unquoted) { | ||
| 132 | 2 | 9µs | my ($name, $code, $captures) = @$quoted; | ||
| 133 | 2 | 800ns | my $package; | ||
| 134 | |||||
| 135 | 2 | 20µs | 2 | 9µs | ($package, $name) = $name =~ /(.*)::(.*)/ # spent 9µs making 2 calls to Sub::Quote::CORE:match, avg 5µs/call |
| 136 | if $name; | ||||
| 137 | |||||
| 138 | 2 | 10µs | my $make_sub = "{\n"; | ||
| 139 | |||||
| 140 | 2 | 8µs | my %captures = $captures ? %$captures : (); | ||
| 141 | 2 | 2µs | $captures{'$_UNQUOTED'} = \$unquoted; | ||
| 142 | 2 | 1µs | $captures{'$_QUOTED'} = \$quoted; | ||
| 143 | 2 | 8µs | 2 | 279µs | $make_sub .= capture_unroll("\$_[1]", \%captures, 2); # spent 279µs making 2 calls to Sub::Quote::capture_unroll, avg 139µs/call |
| 144 | |||||
| 145 | 2 | 4µs | $make_sub .= ( | ||
| 146 | $name | ||||
| 147 | # disable the 'variable $x will not stay shared' warning since | ||||
| 148 | # we're not letting it escape from this scope anyway so there's | ||||
| 149 | # nothing trying to share it | ||||
| 150 | ? " no warnings 'closure';\n package ${package};\n sub ${name} {\n" | ||||
| 151 | : " \$\$_UNQUOTED = sub {\n" | ||||
| 152 | ); | ||||
| 153 | 2 | 900ns | $make_sub .= " (\$_QUOTED,\$_UNQUOTED) if 0;\n"; | ||
| 154 | 2 | 20µs | $make_sub .= $code; | ||
| 155 | 2 | 2µs | $make_sub .= " }".($name ? '' : ';')."\n"; | ||
| 156 | 2 | 2µs | if ($name) { | ||
| 157 | $make_sub .= " \$\$_UNQUOTED = \\&${name}\n"; | ||||
| 158 | } | ||||
| 159 | 2 | 1µs | $make_sub .= "}\n1;\n"; | ||
| 160 | 2 | 2µs | $ENV{SUB_QUOTE_DEBUG} && warn $make_sub; | ||
| 161 | { | ||||
| 162 | 4 | 293µs | 2 | 46µs | # spent 28µs (11+18) within Sub::Quote::BEGIN@162 which was called:
# once (11µs+18µs) by Method::Generate::Constructor::BEGIN@4 at line 162 # spent 28µs making 1 call to Sub::Quote::BEGIN@162
# spent 18µs making 1 call to strict::unimport |
| 163 | 2 | 8µs | local *{"${package}::${name}"} if $name; | ||
| 164 | 2 | 700ns | my ($success, $e); | ||
| 165 | { | ||||
| 166 | 4 | 2µs | local $@; | ||
| 167 | 2 | 6µs | 2 | 1.78ms | $success = _clean_eval($make_sub, \%captures); # spent 1.78ms making 2 calls to Sub::Quote::_clean_eval, avg 892µs/call |
| 168 | 2 | 2µs | $e = $@; | ||
| 169 | } | ||||
| 170 | 2 | 1µs | unless ($success) { | ||
| 171 | die "Eval went very, very wrong:\n\n${make_sub}\n\n$e"; | ||||
| 172 | } | ||||
| 173 | 2 | 18µs | 2 | 4µs | weaken($QUOTED{$$unquoted} = $quoted); # spent 4µs making 2 calls to Scalar::Util::weaken, avg 2µs/call |
| 174 | } | ||||
| 175 | } | ||||
| 176 | 2 | 9µs | $$unquoted; | ||
| 177 | } | ||||
| 178 | |||||
| 179 | sub qsub ($) { | ||||
| 180 | goto "e_sub; | ||||
| 181 | } | ||||
| 182 | |||||
| 183 | sub CLONE { | ||||
| 184 | %QUOTED = map { defined $_ ? ( | ||||
| 185 | $_->[3] && ${$_->[3]} ? (${ $_->[3] } => $_) : (), | ||||
| 186 | $_->[4] ? ($_->[4] => $_) : (), | ||||
| 187 | ) : () } values %QUOTED; | ||||
| 188 | weaken($_) for values %QUOTED; | ||||
| 189 | } | ||||
| 190 | |||||
| 191 | 1 | 4µs | 1; | ||
| 192 | __END__ | ||||
sub Sub::Quote::CORE:match; # opcode | |||||
# spent 12µs within Sub::Quote::CORE:subst which was called 2 times, avg 6µs/call:
# 2 times (12µs+0s) by Sub::Quote::quote_sub at line 80, avg 6µs/call |