From: Brandon Black Date: Mon, 30 Apr 2007 16:45:54 +0000 (-0500) Subject: Re: mro status, etc X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=08aeb9f701fa786d490e79e99ac2f9f9de229da3;p=p5sagit%2Fp5-mst-13.2.git Re: mro status, etc From: "Brandon Black" Message-ID: <84621a60704301445y37e9b05ey235210a8e5547cc1@mail.gmail.com> p4raw-id: //depot/perl@31122 --- diff --git a/embedvar.h b/embedvar.h index 1a4ba0d..da82c87 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 693a0ac..301f7a4 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); +=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 (which is what +C 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 as +opposed to assignment, C<@ISA = (@ISA, qw/A B C/);> +will still be faster than C + =head1 SEE ALSO =head2 The original Dylan paper diff --git a/mg.c b/mg.c index 21f671a..9617767 100644 --- a/mg.c +++ b/mg.c @@ -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; } diff --git a/perlapi.h b/perlapi.h index cf29a35..d09fc33 100644 --- a/perlapi.h +++ b/perlapi.h @@ -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 diff --git a/pp_hot.c b/pp_hot.c index 51f4967..35e8868 100644 --- a/pp_hot.c +++ b/pp_hot.c @@ -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 7aa4a7b..5429315 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 313a4ed..b7bf6d4 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); diff --git a/thrdvar.h b/thrdvar.h index 4f49ef8..3b5bbc1 100644 --- a/thrdvar.h +++ b/thrdvar.h @@ -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