#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)
#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
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
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;
}
#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
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;
}
}
require './test.pl';
-use mro;
plan(skip_all => "Your system has no SIGALRM") if !exists $SIG{ALRM};
plan(tests => 8);
}
require './test.pl';
-use mro;
plan(skip_all => "Your system has no SIGALRM") if !exists $SIG{ALRM};
plan(tests => 8);
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