| Filename | /2home/ss5/perl5/perlbrew/perls/perl-5.12.3/lib/site_perl/5.12.3/Class/C3.pm |
| Statements | Executed 62 statements in 1.23ms |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 209µs | 431µs | Class::C3::BEGIN@12 |
| 5 | 5 | 5 | 41µs | 56µs | Class::C3::import |
| 1 | 1 | 1 | 11µs | 13µs | Class::C3::BEGIN@4 |
| 1 | 1 | 1 | 8µs | 24µs | Class::C3::BEGIN@83 |
| 1 | 1 | 1 | 6µs | 14µs | Class::C3::BEGIN@218 |
| 1 | 1 | 1 | 6µs | 20µs | Class::C3::BEGIN@172 |
| 1 | 1 | 1 | 6µs | 13µs | Class::C3::BEGIN@5 |
| 1 | 1 | 1 | 6µs | 13µs | Class::C3::BEGIN@222 |
| 1 | 1 | 1 | 6µs | 18µs | Class::C3::BEGIN@133 |
| 1 | 1 | 1 | 5µs | 13µs | Class::C3::BEGIN@195 |
| 1 | 1 | 1 | 5µs | 13µs | Class::C3::BEGIN@208 |
| 0 | 0 | 0 | 0s | 0s | Class::C3::__ANON__[:210] |
| 0 | 0 | 0 | 0s | 0s | Class::C3::_apply_method_dispatch_table |
| 0 | 0 | 0 | 0s | 0s | Class::C3::_apply_method_dispatch_tables |
| 0 | 0 | 0 | 0s | 0s | Class::C3::_calculate_method_dispatch_table |
| 0 | 0 | 0 | 0s | 0s | Class::C3::_calculate_method_dispatch_tables |
| 0 | 0 | 0 | 0s | 0s | Class::C3::_core_calculateMRO |
| 0 | 0 | 0 | 0s | 0s | Class::C3::_dump_MRO_table |
| 0 | 0 | 0 | 0s | 0s | Class::C3::_remove_method_dispatch_table |
| 0 | 0 | 0 | 0s | 0s | Class::C3::_remove_method_dispatch_tables |
| 0 | 0 | 0 | 0s | 0s | Class::C3::calculateMRO |
| 0 | 0 | 0 | 0s | 0s | Class::C3::initialize |
| 0 | 0 | 0 | 0s | 0s | Class::C3::reinitialize |
| 0 | 0 | 0 | 0s | 0s | Class::C3::uninitialize |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | |||||
| 2 | package Class::C3; | ||||
| 3 | |||||
| 4 | 3 | 16µs | 2 | 16µs | # spent 13µs (11+3) within Class::C3::BEGIN@4 which was called:
# once (11µs+3µs) by main::BEGIN@7 at line 4 # spent 13µs making 1 call to Class::C3::BEGIN@4
# spent 3µs making 1 call to strict::import |
| 5 | 3 | 127µs | 2 | 20µs | # spent 13µs (6+7) within Class::C3::BEGIN@5 which was called:
# once (6µs+7µs) by main::BEGIN@7 at line 5 # spent 13µs making 1 call to Class::C3::BEGIN@5
# spent 7µs making 1 call to warnings::import |
| 6 | |||||
| 7 | 1 | 400ns | our $VERSION = '0.24'; | ||
| 8 | |||||
| 9 | 1 | 200ns | our $C3_IN_CORE; | ||
| 10 | 1 | 0s | our $C3_XS; | ||
| 11 | |||||
| 12 | # spent 431µs (209+222) within Class::C3::BEGIN@12 which was called:
# once (209µs+222µs) by main::BEGIN@7 at line 39 | ||||
| 13 | 3 | 69µs | if($] > 5.009_004) { | ||
| 14 | $C3_IN_CORE = 1; | ||||
| 15 | require mro; | ||||
| 16 | } | ||||
| 17 | elsif($C3_XS or not defined $C3_XS) { | ||||
| 18 | my $error = do { | ||||
| 19 | local $@; | ||||
| 20 | eval { require Class::C3::XS }; | ||||
| 21 | $@; | ||||
| 22 | }; | ||||
| 23 | |||||
| 24 | if ($error) { | ||||
| 25 | die $error if $error !~ /\blocate\b/; | ||||
| 26 | |||||
| 27 | if ($C3_XS) { | ||||
| 28 | require Carp; | ||||
| 29 | Carp::croak( "XS explicitly requested but Class::C3::XS is not available" ); | ||||
| 30 | } | ||||
| 31 | |||||
| 32 | require Algorithm::C3; | ||||
| 33 | require Class::C3::next; | ||||
| 34 | } | ||||
| 35 | else { | ||||
| 36 | $C3_XS = 1; | ||||
| 37 | } | ||||
| 38 | } | ||||
| 39 | 1 | 103µs | 1 | 431µs | } # spent 431µs making 1 call to Class::C3::BEGIN@12 |
| 40 | |||||
| 41 | # this is our global stash of both | ||||
| 42 | # MRO's and method dispatch tables | ||||
| 43 | # the structure basically looks like | ||||
| 44 | # this: | ||||
| 45 | # | ||||
| 46 | # $MRO{$class} = { | ||||
| 47 | # MRO => [ <class precendence list> ], | ||||
| 48 | # methods => { | ||||
| 49 | # orig => <original location of method>, | ||||
| 50 | # code => \&<ref to original method> | ||||
| 51 | # }, | ||||
| 52 | # has_overload_fallback => (1 | 0) | ||||
| 53 | # } | ||||
| 54 | # | ||||
| 55 | 1 | 200ns | our %MRO; | ||
| 56 | |||||
| 57 | # use these for debugging ... | ||||
| 58 | sub _dump_MRO_table { %MRO } | ||||
| 59 | 1 | 200ns | our $TURN_OFF_C3 = 0; | ||
| 60 | |||||
| 61 | # state tracking for initialize()/uninitialize() | ||||
| 62 | 1 | 300ns | our $_initialized = 0; | ||
| 63 | |||||
| 64 | # spent 56µs (41+15) within Class::C3::import which was called 5 times, avg 11µs/call:
# once (12µs+6µs) by Tapper::Model::BEGIN@21 at line 21 of Tapper/Model.pm
# once (11µs+4µs) by Tapper::Schema::TestTools::BEGIN@15 at line 15 of Tapper/Schema/TestTools.pm
# once (11µs+3µs) by Tapper::Schema::ReportsDB::BEGIN@21 at line 21 of Tapper/Schema/ReportsDB.pm
# once (5µs+2µs) by Tapper::Schema::TestrunDB::BEGIN@20 at line 20 of Tapper/Schema/TestrunDB.pm
# once (2µs+0s) by main::BEGIN@7 at line 7 of xt/tapper-mcp-scheduler-with-db-longrun.t | ||||
| 65 | 22 | 66µs | my $class = caller(); | ||
| 66 | # skip if the caller is main:: | ||||
| 67 | # since that is clearly not relevant | ||||
| 68 | return if $class eq 'main'; | ||||
| 69 | |||||
| 70 | return if $TURN_OFF_C3; | ||||
| 71 | 4 | 15µs | mro::set_mro($class, 'c3') if $C3_IN_CORE; # spent 15µs making 4 calls to mro::set_mro, avg 4µs/call | ||
| 72 | |||||
| 73 | # make a note to calculate $class | ||||
| 74 | # during INIT phase | ||||
| 75 | $MRO{$class} = undef unless exists $MRO{$class}; | ||||
| 76 | } | ||||
| 77 | |||||
| 78 | ## initializers | ||||
| 79 | |||||
| 80 | # This prevents silly warnings when Class::C3 is | ||||
| 81 | # used explicitly along with MRO::Compat under 5.9.5+ | ||||
| 82 | |||||
| 83 | 4 | 220µs | 2 | 40µs | # spent 24µs (8+16) within Class::C3::BEGIN@83 which was called:
# once (8µs+16µs) by main::BEGIN@7 at line 83 # spent 24µs making 1 call to Class::C3::BEGIN@83
# spent 16µs making 1 call to warnings::unimport |
| 84 | |||||
| 85 | sub initialize { | ||||
| 86 | %next::METHOD_CACHE = (); | ||||
| 87 | # why bother if we don't have anything ... | ||||
| 88 | return unless keys %MRO; | ||||
| 89 | if($C3_IN_CORE) { | ||||
| 90 | mro::set_mro($_, 'c3') for keys %MRO; | ||||
| 91 | } | ||||
| 92 | else { | ||||
| 93 | if($_initialized) { | ||||
| 94 | uninitialize(); | ||||
| 95 | $MRO{$_} = undef foreach keys %MRO; | ||||
| 96 | } | ||||
| 97 | _calculate_method_dispatch_tables(); | ||||
| 98 | _apply_method_dispatch_tables(); | ||||
| 99 | $_initialized = 1; | ||||
| 100 | } | ||||
| 101 | } | ||||
| 102 | |||||
| 103 | sub uninitialize { | ||||
| 104 | # why bother if we don't have anything ... | ||||
| 105 | %next::METHOD_CACHE = (); | ||||
| 106 | return unless keys %MRO; | ||||
| 107 | if($C3_IN_CORE) { | ||||
| 108 | mro::set_mro($_, 'dfs') for keys %MRO; | ||||
| 109 | } | ||||
| 110 | else { | ||||
| 111 | _remove_method_dispatch_tables(); | ||||
| 112 | $_initialized = 0; | ||||
| 113 | } | ||||
| 114 | } | ||||
| 115 | |||||
| 116 | sub reinitialize { goto &initialize } | ||||
| 117 | |||||
| 118 | } # end of "no warnings 'redefine'" | ||||
| 119 | |||||
| 120 | ## functions for applying C3 to classes | ||||
| 121 | |||||
| 122 | sub _calculate_method_dispatch_tables { | ||||
| 123 | return if $C3_IN_CORE; | ||||
| 124 | my %merge_cache; | ||||
| 125 | foreach my $class (keys %MRO) { | ||||
| 126 | _calculate_method_dispatch_table($class, \%merge_cache); | ||||
| 127 | } | ||||
| 128 | } | ||||
| 129 | |||||
| 130 | sub _calculate_method_dispatch_table { | ||||
| 131 | return if $C3_IN_CORE; | ||||
| 132 | my ($class, $merge_cache) = @_; | ||||
| 133 | 3 | 210µs | 2 | 31µs | # spent 18µs (6+13) within Class::C3::BEGIN@133 which was called:
# once (6µs+13µs) by main::BEGIN@7 at line 133 # spent 18µs making 1 call to Class::C3::BEGIN@133
# spent 13µs making 1 call to strict::unimport |
| 134 | my @MRO = calculateMRO($class, $merge_cache); | ||||
| 135 | $MRO{$class} = { MRO => \@MRO }; | ||||
| 136 | my $has_overload_fallback; | ||||
| 137 | my %methods; | ||||
| 138 | # NOTE: | ||||
| 139 | # we do @MRO[1 .. $#MRO] here because it | ||||
| 140 | # makes no sense to interogate the class | ||||
| 141 | # which you are calculating for. | ||||
| 142 | foreach my $local (@MRO[1 .. $#MRO]) { | ||||
| 143 | # if overload has tagged this module to | ||||
| 144 | # have use "fallback", then we want to | ||||
| 145 | # grab that value | ||||
| 146 | $has_overload_fallback = ${"${local}::()"} | ||||
| 147 | if !defined $has_overload_fallback && defined ${"${local}::()"}; | ||||
| 148 | foreach my $method (grep { defined &{"${local}::$_"} } keys %{"${local}::"}) { | ||||
| 149 | # skip if already overriden in local class | ||||
| 150 | next unless !defined *{"${class}::$method"}{CODE}; | ||||
| 151 | $methods{$method} = { | ||||
| 152 | orig => "${local}::$method", | ||||
| 153 | code => \&{"${local}::$method"} | ||||
| 154 | } unless exists $methods{$method}; | ||||
| 155 | } | ||||
| 156 | } | ||||
| 157 | # now stash them in our %MRO table | ||||
| 158 | $MRO{$class}->{methods} = \%methods; | ||||
| 159 | $MRO{$class}->{has_overload_fallback} = $has_overload_fallback; | ||||
| 160 | } | ||||
| 161 | |||||
| 162 | sub _apply_method_dispatch_tables { | ||||
| 163 | return if $C3_IN_CORE; | ||||
| 164 | foreach my $class (keys %MRO) { | ||||
| 165 | _apply_method_dispatch_table($class); | ||||
| 166 | } | ||||
| 167 | } | ||||
| 168 | |||||
| 169 | sub _apply_method_dispatch_table { | ||||
| 170 | return if $C3_IN_CORE; | ||||
| 171 | my $class = shift; | ||||
| 172 | 3 | 161µs | 2 | 34µs | # spent 20µs (6+14) within Class::C3::BEGIN@172 which was called:
# once (6µs+14µs) by main::BEGIN@7 at line 172 # spent 20µs making 1 call to Class::C3::BEGIN@172
# spent 14µs making 1 call to strict::unimport |
| 173 | ${"${class}::()"} = $MRO{$class}->{has_overload_fallback} | ||||
| 174 | if !defined &{"${class}::()"} | ||||
| 175 | && defined $MRO{$class}->{has_overload_fallback}; | ||||
| 176 | foreach my $method (keys %{$MRO{$class}->{methods}}) { | ||||
| 177 | if ( $method =~ /^\(/ ) { | ||||
| 178 | my $orig = $MRO{$class}->{methods}->{$method}->{orig}; | ||||
| 179 | ${"${class}::$method"} = $$orig if defined $$orig; | ||||
| 180 | } | ||||
| 181 | *{"${class}::$method"} = $MRO{$class}->{methods}->{$method}->{code}; | ||||
| 182 | } | ||||
| 183 | } | ||||
| 184 | |||||
| 185 | sub _remove_method_dispatch_tables { | ||||
| 186 | return if $C3_IN_CORE; | ||||
| 187 | foreach my $class (keys %MRO) { | ||||
| 188 | _remove_method_dispatch_table($class); | ||||
| 189 | } | ||||
| 190 | } | ||||
| 191 | |||||
| 192 | sub _remove_method_dispatch_table { | ||||
| 193 | return if $C3_IN_CORE; | ||||
| 194 | my $class = shift; | ||||
| 195 | 3 | 103µs | 2 | 21µs | # spent 13µs (5+8) within Class::C3::BEGIN@195 which was called:
# once (5µs+8µs) by main::BEGIN@7 at line 195 # spent 13µs making 1 call to Class::C3::BEGIN@195
# spent 8µs making 1 call to strict::unimport |
| 196 | delete ${"${class}::"}{"()"} if $MRO{$class}->{has_overload_fallback}; | ||||
| 197 | foreach my $method (keys %{$MRO{$class}->{methods}}) { | ||||
| 198 | delete ${"${class}::"}{$method} | ||||
| 199 | if defined *{"${class}::${method}"}{CODE} && | ||||
| 200 | (*{"${class}::${method}"}{CODE} eq $MRO{$class}->{methods}->{$method}->{code}); | ||||
| 201 | } | ||||
| 202 | } | ||||
| 203 | |||||
| 204 | sub calculateMRO { | ||||
| 205 | my ($class, $merge_cache) = @_; | ||||
| 206 | |||||
| 207 | return Algorithm::C3::merge($class, sub { | ||||
| 208 | 3 | 63µs | 2 | 20µs | # spent 13µs (5+8) within Class::C3::BEGIN@208 which was called:
# once (5µs+8µs) by main::BEGIN@7 at line 208 # spent 13µs making 1 call to Class::C3::BEGIN@208
# spent 7µs making 1 call to strict::unimport |
| 209 | @{$_[0] . '::ISA'}; | ||||
| 210 | }, $merge_cache); | ||||
| 211 | } | ||||
| 212 | |||||
| 213 | # Method overrides to support 5.9.5+ or Class::C3::XS | ||||
| 214 | |||||
| 215 | sub _core_calculateMRO { @{mro::get_linear_isa($_[0], 'c3')} } | ||||
| 216 | |||||
| 217 | 1 | 300ns | if($C3_IN_CORE) { | ||
| 218 | 3 | 30µs | 2 | 21µs | # spent 14µs (6+8) within Class::C3::BEGIN@218 which was called:
# once (6µs+8µs) by main::BEGIN@7 at line 218 # spent 14µs making 1 call to Class::C3::BEGIN@218
# spent 8µs making 1 call to warnings::unimport |
| 219 | 1 | 7µs | *Class::C3::calculateMRO = \&_core_calculateMRO; | ||
| 220 | } | ||||
| 221 | elsif($C3_XS) { | ||||
| 222 | 3 | 44µs | 2 | 20µs | # spent 13µs (6+7) within Class::C3::BEGIN@222 which was called:
# once (6µs+7µs) by main::BEGIN@7 at line 222 # spent 13µs making 1 call to Class::C3::BEGIN@222
# spent 7µs making 1 call to warnings::unimport |
| 223 | *Class::C3::calculateMRO = \&Class::C3::XS::calculateMRO; | ||||
| 224 | *Class::C3::_calculate_method_dispatch_table | ||||
| 225 | = \&Class::C3::XS::_calculate_method_dispatch_table; | ||||
| 226 | } | ||||
| 227 | |||||
| 228 | 1 | 7µs | 1; | ||
| 229 | |||||
| 230 | __END__ |