diff options
-rw-r--r-- | embedvar.h | 2 | ||||
-rw-r--r-- | lib/mro.pm | 33 | ||||
-rw-r--r-- | mg.c | 19 | ||||
-rw-r--r-- | perlapi.h | 2 | ||||
-rw-r--r-- | pp_hot.c | 9 | ||||
-rw-r--r-- | t/mro/recursion_c3.t | 1 | ||||
-rw-r--r-- | t/mro/recursion_dfs.t | 1 | ||||
-rw-r--r-- | thrdvar.h | 1 |
8 files changed, 60 insertions, 8 deletions
diff --git a/embedvar.h b/embedvar.h index 1a4ba0db49..da82c87306 100644 --- a/embedvar.h +++ b/embedvar.h @@ -55,6 +55,7 @@ #define PL_curstash (vTHX->Tcurstash) #define PL_defoutgv (vTHX->Tdefoutgv) #define PL_defstash (vTHX->Tdefstash) +#define PL_delayedisa (vTHX->Tdelayedisa) #define PL_delaymagic (vTHX->Tdelaymagic) #define PL_dirty (vTHX->Tdirty) #define PL_dumpindent (vTHX->Tdumpindent) @@ -661,6 +662,7 @@ #define PL_Tcurstash PL_curstash #define PL_Tdefoutgv PL_defoutgv #define PL_Tdefstash PL_defstash +#define PL_Tdelayedisa PL_delayedisa #define PL_Tdelaymagic PL_delaymagic #define PL_Tdirty PL_dirty #define PL_Tdumpindent PL_dumpindent diff --git a/lib/mro.pm b/lib/mro.pm index 693a0ac49d..301f7a433c 100644 --- a/lib/mro.pm +++ b/lib/mro.pm @@ -246,6 +246,39 @@ In simple cases, it is equivalent to: But there are some cases where only this solution works (like C<goto &maybe::next::method>); +=head1 PERFORMANCE CONSIDERATIONS + +Specifying the mro type of a class before setting C<@ISA> will +be faster than the other way around. Also, making all of your +C<@ISA> manipulations in a single assignment statement will be +faster that doing them one by one via C<push> (which is what +C<use base> does currently). + +Examples: + + # The slowest way + package Foo; + use base qw/A B C/; + use mro 'c3'; + + # The fastest way + # (not exactly equivalent to above, + # as base.pm can do other magic) + use mro 'c3'; + use A (); + use B (); + use C (); + our @ISA = qw/A B C/; + +Generally speaking, every time C<@ISA> is modified, the MRO +of that class will be recalculated, because of the way array +magic works. Pushing multiple items onto C<@ISA> in one push +statement still counts as multiple modifications. However, +assigning a list to C<@ISA> only counts as a single +modification. Thus if you really need to do C<push> as +opposed to assignment, C<@ISA = (@ISA, qw/A B C/);> +will still be faster than C<push(@ISA, qw/A B C/);> + =head1 SEE ALSO =head2 The original Dylan paper @@ -1529,19 +1529,26 @@ int Perl_magic_setisa(pTHX_ SV *sv, MAGIC *mg) { dVAR; + HV* stash; PERL_UNUSED_ARG(sv); + /* Bail out if destruction is going on */ + if(PL_dirty) return 0; + /* The first case occurs via setisa, the second via setisa_elem, which calls this same magic */ - mro_isa_changed_in( - GvSTASH( - SvTYPE(mg->mg_obj) == SVt_PVGV - ? (GV*)mg->mg_obj - : (GV*)SvMAGIC(mg->mg_obj)->mg_obj - ) + stash = GvSTASH( + SvTYPE(mg->mg_obj) == SVt_PVGV + ? (GV*)mg->mg_obj + : (GV*)SvMAGIC(mg->mg_obj)->mg_obj ); + if(PL_delaymagic) + PL_delayedisa = stash; + else + mro_isa_changed_in(stash); + return 0; } @@ -668,6 +668,8 @@ END_EXTERN_C #define PL_defoutgv (*Perl_Tdefoutgv_ptr(aTHX)) #undef PL_defstash #define PL_defstash (*Perl_Tdefstash_ptr(aTHX)) +#undef PL_delayedisa +#define PL_delayedisa (*Perl_Tdelayedisa_ptr(aTHX)) #undef PL_delaymagic #define PL_delaymagic (*Perl_Tdelaymagic_ptr(aTHX)) #undef PL_dirty @@ -1151,6 +1151,15 @@ PP(pp_aassign) while (relem <= SP) *relem++ = (lelem <= lastlelem) ? *lelem++ : &PL_sv_undef; } + + /* This is done at the bottom and in this order because + mro_isa_changed_in() can throw exceptions */ + if(PL_delayedisa) { + HV* stash = PL_delayedisa; + PL_delayedisa = NULL; + mro_isa_changed_in(stash); + } + RETURN; } diff --git a/t/mro/recursion_c3.t b/t/mro/recursion_c3.t index 7aa4a7b866..54293150e0 100644 --- a/t/mro/recursion_c3.t +++ b/t/mro/recursion_c3.t @@ -10,7 +10,6 @@ BEGIN { } require './test.pl'; -use mro; plan(skip_all => "Your system has no SIGALRM") if !exists $SIG{ALRM}; plan(tests => 8); diff --git a/t/mro/recursion_dfs.t b/t/mro/recursion_dfs.t index 313a4ed562..b7bf6d42cd 100644 --- a/t/mro/recursion_dfs.t +++ b/t/mro/recursion_dfs.t @@ -10,7 +10,6 @@ BEGIN { } require './test.pl'; -use mro; plan(skip_all => "Your system has no SIGALRM") if !exists $SIG{ALRM}; plan(tests => 8); @@ -182,6 +182,7 @@ PERLVAR(Tcolorset, bool) /* from regcomp.c */ PERLVARI(Tdirty, bool, FALSE) /* in the middle of tearing things down? */ PERLVAR(Tin_eval, VOL U8) /* trap "fatal" errors? */ PERLVAR(Ttainted, bool) /* using variables controlled by $< */ +PERLVARI(Tdelayedisa, HV*, NULL) /* stash for PL_delaymagic for magic_setisa */ /* For historical reasons this file is followed by intrpvar.h in the interpeter struct. As this file currently ends with 7 bytes of variables, intrpvar.h |