summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embedvar.h2
-rw-r--r--lib/mro.pm33
-rw-r--r--mg.c19
-rw-r--r--perlapi.h2
-rw-r--r--pp_hot.c9
-rw-r--r--t/mro/recursion_c3.t1
-rw-r--r--t/mro/recursion_dfs.t1
-rw-r--r--thrdvar.h1
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
diff --git a/mg.c b/mg.c
index 21f671adc5..9617767165 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 cf29a35491..d09fc33fa3 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 51f496798c..35e88688c1 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 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);
diff --git a/thrdvar.h b/thrdvar.h
index 4f49ef8442..3b5bbc10e9 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