summaryrefslogtreecommitdiff
path: root/universal.c
diff options
context:
space:
mode:
authorNicholas Clark <nick@ccl4.org>2008-09-12 00:19:51 +0000
committerNicholas Clark <nick@ccl4.org>2008-09-12 00:19:51 +0000
commita49ba3fcbe357fbacf7b9898df08daa2cbdfc8c4 (patch)
tree43834e70391760038633daf86cecae00b95fef4e /universal.c
parentc109477dfda0dedbe3c4ffa3d6074085d3b8497a (diff)
downloadperl-a49ba3fcbe357fbacf7b9898df08daa2cbdfc8c4.tar.gz
Create a direct lookup hash for ->isa() lookup, by retaining the
de-duping hash used by S_mro_get_linear_isa_dfs(). Provide a new function Perl_get_isa_hash() to lazily retrieve this. (Which could actually be static if S_isa_lookup() and Perl_sv_derived_from() moved into mro.c.) Make S_isa_lookup() use this lookup hash in place of a linear walk of the linear isa. This should turn isa lookups from O(n) to O(1), which should make heavy users of ->isa() faster. (eg PPI, and hence Perl Critic). p4raw-id: //depot/perl@34354
Diffstat (limited to 'universal.c')
-rw-r--r--universal.c41
1 files changed, 19 insertions, 22 deletions
diff --git a/universal.c b/universal.c
index 08dad15ab5..de928f7d13 100644
--- a/universal.c
+++ b/universal.c
@@ -40,35 +40,32 @@ STATIC bool
S_isa_lookup(pTHX_ HV *stash, const char * const name)
{
dVAR;
- AV* stash_linear_isa;
- SV** svp;
- const char *hvname;
- I32 items;
- const HV *const name_stash = gv_stashpv(name, 0);
+ const struct mro_meta *const meta = HvMROMETA(stash);
+ HV *const isa = meta->isa ? meta->isa : Perl_get_isa_hash(aTHX_ stash);
+ STRLEN len = strlen(name);
+ const HV *our_stash;
PERL_ARGS_ASSERT_ISA_LOOKUP;
- /* A stash/class can go by many names (ie. User == main::User), so
- we compare the stash itself just in case */
- if ((const HV *)stash == name_stash)
- return TRUE;
-
- hvname = HvNAME_get(stash);
-
- if (strEQ(hvname, name))
+ if (hv_common(isa, NULL, name, len, 0 /* No "UTF-8" flag possible with only
+ a char * argument*/,
+ HV_FETCH_ISEXISTS, NULL, 0)) {
+ /* Direct name lookup worked. */
return TRUE;
+ }
- if (strEQ(name, "UNIVERSAL"))
- return TRUE;
+ /* A stash/class can go by many names (ie. User == main::User), so
+ we use the name in the stash itself, which is canonical. */
+ our_stash = gv_stashpvn(name, len, 0);
- stash_linear_isa = mro_get_linear_isa(stash);
- svp = AvARRAY(stash_linear_isa) + 1;
- items = AvFILLp(stash_linear_isa);
- while (items--) {
- SV* const basename_sv = *svp++;
- HV* const basestash = gv_stashsv(basename_sv, 0);
- if(name_stash == basestash || strEQ(name, SvPVX(basename_sv)))
+ if (our_stash) {
+ HEK *const canon_name = HvNAME_HEK(our_stash);
+
+ if (hv_common(isa, NULL, HEK_KEY(canon_name), HEK_LEN(canon_name),
+ HEK_FLAGS(canon_name),
+ HV_FETCH_ISEXISTS, NULL, HEK_HASH(canon_name))) {
return TRUE;
+ }
}
return FALSE;