Refactor how prehashed hash keys work.
Florian Ragwitz [Wed, 11 Mar 2009 03:39:13 +0000 (04:39 +0100)]
mop.c
mop.h
xs/Attribute.xs
xs/Class.xs
xs/MOP.xs
xs/Method.xs
xs/Package.xs

diff --git a/mop.c b/mop.c
index 688634d..08e5349 100644 (file)
--- a/mop.c
+++ b/mop.c
@@ -201,3 +201,44 @@ mop_get_all_package_symbols (HV *stash, type_filter_t filter)
     mop_get_package_symbols (stash, filter, collect_all_symbols, ret);
     return ret;
 }
+
+/* the order of these has to match with those in mop.h */
+static struct {
+    const char *name;
+    const char *value;
+    SV *key;
+    U32 hash;
+} prehashed_keys[key_last] = {
+    DECLARE_KEY(name),
+    DECLARE_KEY(package),
+    DECLARE_KEY(package_name),
+    DECLARE_KEY(body),
+    DECLARE_KEY_WITH_VALUE(package_cache_flag, "_package_cache_flag"),
+    DECLARE_KEY(methods),
+    DECLARE_KEY(VERSION),
+    DECLARE_KEY(ISA)
+};
+
+inline SV *
+mop_prehashed_key_for (mop_prehashed_key_t key)
+{
+    return prehashed_keys[key].key;
+}
+
+inline U32
+mop_prehashed_hash_for (mop_prehashed_key_t key)
+{
+    return prehashed_keys[key].hash;
+}
+
+void
+mop_prehash_keys ()
+{
+    int i;
+
+    for (i = 0; i < key_last; i++) {
+        const char *value = prehashed_keys[i].value;
+        prehashed_keys[i].key = newSVpv(value, strlen(value));
+        PERL_HASH(prehashed_keys[i].hash, value, strlen(value));
+    }
+}
diff --git a/mop.h b/mop.h
index bdbff08..444f8ac 100644 (file)
--- a/mop.h
+++ b/mop.h
 
 void mop_call_xs (pTHX_ void (*subaddr) (pTHX_ CV *), CV *cv, SV **mark);
 
-#define DECLARE_KEY(name) SV *key_##name; U32 hash_##name;
-#define NEEDS_KEY(name) extern SV *key_##name; extern U32 hash_##name;
-
-#define PREHASH_KEY_WITH_VALUE(name, value) do { \
-    key_##name = newSVpvs(value); \
-    PERL_HASH(hash_##name, value, sizeof(value) - 1); \
-} while (0)
-
-/* this is basically the same as the above macro, except that the value will be
- * the stringified name. However, we can't just implement this in terms of
- * PREHASH_KEY_WITH_VALUE as that'd cause macro expansion on the value of
- * 'name' when it's being passed to the other macro. suggestions on how to make
- * this more elegant would be much appreciated */
-
-#define PREHASH_KEY(name) do { \
-    key_##name = newSVpvs(#name); \
-    PERL_HASH(hash_##name, #name, sizeof(#name) - 1); \
-} while (0)
+#define DECLARE_KEY(name)                    { #name, #name, NULL, 0 }
+#define DECLARE_KEY_WITH_VALUE(name, value)  { #name, value, NULL, 0 }
+
+typedef enum {
+    KEY_name,
+    KEY_package,
+    KEY_package_name,
+    KEY_body,
+    KEY_package_cache_flag,
+    KEY_methods,
+    KEY_VERSION,
+    KEY_ISA,
+    key_last,
+} mop_prehashed_key_t;
+
+#define KEY_FOR(name)  mop_prehashed_key_for(KEY_ ##name)
+#define HASH_FOR(name) mop_prehashed_hash_for(KEY_ ##name)
+
+void mop_prehash_keys (void);
+inline SV *mop_prehashed_key_for (mop_prehashed_key_t key);
+inline U32 mop_prehashed_hash_for (mop_prehashed_key_t key);
 
 extern SV *mop_method_metaclass;
 extern SV *mop_associated_metaclass;
index 807e7e5..150fd05 100644 (file)
@@ -1,7 +1,5 @@
 #include "mop.h"
 
-NEEDS_KEY(name);
-
 MODULE = Class::MOP::Attribute   PACKAGE = Class::MOP::Attribute
 
 PROTOTYPES: DISABLE
@@ -16,7 +14,7 @@ name(self)
             die("Cannot call name as a class method");
         }
 
-        if ( (he = hv_fetch_ent((HV *)SvRV(self), key_name, 0, hash_name)) )
+        if ( (he = hv_fetch_ent((HV *)SvRV(self), KEY_FOR(name), 0, HASH_FOR(name))) )
             XPUSHs(HeVAL(he));
         else
             ST(0) = &PL_sv_undef;
index c332b89..32bbde6 100644 (file)
@@ -1,12 +1,5 @@
 #include "mop.h"
 
-NEEDS_KEY(name);
-NEEDS_KEY(body);
-NEEDS_KEY(methods);
-NEEDS_KEY(package);
-NEEDS_KEY(package_name);
-NEEDS_KEY(package_cache_flag);
-
 static void
 mop_update_method_map(pTHX_ SV *const self, SV *const class_name, HV *const stash, HV *const map)
 {
@@ -41,7 +34,7 @@ mop_update_method_map(pTHX_ SV *const self, SV *const class_name, HV *const stas
 
         method_slot = *hv_fetch(map, method_name, method_name_len, TRUE);
         if ( SvOK(method_slot) ) {
-            SV *const body = mop_call0(aTHX_ method_slot, key_body); /* $method_object->body() */
+            SV *const body = mop_call0(aTHX_ method_slot, KEY_FOR(body)); /* $method_object->body() */
             if ( SvROK(body) && ((CV *) SvRV(body)) == cv ) {
                 continue;
             }
@@ -66,9 +59,9 @@ mop_update_method_map(pTHX_ SV *const self, SV *const class_name, HV *const stas
         mPUSHs(newRV_inc((SV *)cv));
         PUSHs(mop_associated_metaclass);
         PUSHs(self);
-        PUSHs(key_package_name);
+        PUSHs(KEY_FOR(package_name));
         PUSHs(class_name);
-        PUSHs(key_name);
+        PUSHs(KEY_FOR(name));
         mPUSHs(newSVpv(method_name, method_name_len));
         PUTBACK;
 
@@ -93,11 +86,11 @@ get_method_map(self)
     SV *self
     PREINIT:
         HV *const obj        = (HV *)SvRV(self);
-        SV *const class_name = HeVAL( hv_fetch_ent(obj, key_package, 0, hash_package) );
+        SV *const class_name = HeVAL( hv_fetch_ent(obj, KEY_FOR(package), 0, HASH_FOR(package)) );
         HV *const stash      = gv_stashsv(class_name, 0);
         UV  const current    = mop_check_package_cache_flag(aTHX_ stash);
-        SV *const cache_flag = HeVAL( hv_fetch_ent(obj, key_package_cache_flag, TRUE, hash_package_cache_flag));
-        SV *const map_ref    = HeVAL( hv_fetch_ent(obj, key_methods, TRUE, hash_methods));
+        SV *const cache_flag = HeVAL( hv_fetch_ent(obj, KEY_FOR(package_cache_flag), TRUE, HASH_FOR(package_cache_flag)));
+        SV *const map_ref    = HeVAL( hv_fetch_ent(obj, KEY_FOR(methods), TRUE, HASH_FOR(methods)));
     PPCODE:
         /* in  $self->{methods} does not yet exist (or got deleted) */
         if ( !SvROK(map_ref) || SvTYPE(SvRV(map_ref)) != SVt_PVHV ) {
index 5168786..f3a6384 100644 (file)
--- a/xs/MOP.xs
+++ b/xs/MOP.xs
@@ -8,15 +8,6 @@ find_method (const char *key, STRLEN keylen, SV *val, void *ud)
     return FALSE;
 }
 
-DECLARE_KEY(name);
-DECLARE_KEY(package);
-DECLARE_KEY(package_name);
-DECLARE_KEY(body);
-DECLARE_KEY(package_cache_flag);
-DECLARE_KEY(methods);
-DECLARE_KEY(VERSION);
-DECLARE_KEY(ISA);
-
 SV *mop_method_metaclass;
 SV *mop_associated_metaclass;
 SV *mop_wrap;
@@ -26,14 +17,7 @@ MODULE = Class::MOP   PACKAGE = Class::MOP
 PROTOTYPES: DISABLE
 
 BOOT:
-    PREHASH_KEY(name);
-    PREHASH_KEY(body);
-    PREHASH_KEY(package);
-    PREHASH_KEY(package_name);
-    PREHASH_KEY(methods);
-    PREHASH_KEY(ISA);
-    PREHASH_KEY(VERSION);
-    PREHASH_KEY_WITH_VALUE(package_cache_flag, "_package_cache_flag");
+    mop_prehash_keys();
 
     mop_method_metaclass     = newSVpvs("method_metaclass");
     mop_wrap                 = newSVpvs("wrap");
@@ -78,8 +62,8 @@ is_class_loaded(klass=&PL_sv_undef)
             XSRETURN_NO;
         }
 
-        if (hv_exists_ent (stash, key_VERSION, hash_VERSION)) {
-            HE *version = hv_fetch_ent(stash, key_VERSION, 0, hash_VERSION);
+        if (hv_exists_ent (stash, KEY_FOR(VERSION), HASH_FOR(VERSION))) {
+            HE *version = hv_fetch_ent(stash, KEY_FOR(VERSION), 0, HASH_FOR(VERSION));
             SV *version_sv;
             if (version && HeVAL(version) && (version_sv = GvSV(HeVAL(version)))) {
                 if (SvROK(version_sv)) {
@@ -95,8 +79,8 @@ is_class_loaded(klass=&PL_sv_undef)
             }
         }
 
-        if (hv_exists_ent (stash, key_ISA, hash_ISA)) {
-            HE *isa = hv_fetch_ent(stash, key_ISA, 0, hash_ISA);
+        if (hv_exists_ent (stash, KEY_FOR(ISA), HASH_FOR(ISA))) {
+            HE *isa = hv_fetch_ent(stash, KEY_FOR(ISA), 0, HASH_FOR(ISA));
             if (isa && HeVAL(isa) && GvAV(HeVAL(isa))) {
                 XSRETURN_YES;
             }
index 18865bc..ba2c850 100644 (file)
@@ -1,9 +1,5 @@
 #include "mop.h"
 
-NEEDS_KEY(name);
-NEEDS_KEY(body);
-NEEDS_KEY(package_name);
-
 MODULE = Class::MOP::Method   PACKAGE = Class::MOP::Method
 
 PROTOTYPES: DISABLE
@@ -18,7 +14,7 @@ name(self)
             die("Cannot call name as a class method");
         }
 
-        if ( (he = hv_fetch_ent((HV *)SvRV(self), key_name, 0, hash_name)) )
+        if ( (he = hv_fetch_ent((HV *)SvRV(self), KEY_FOR(name), 0, HASH_FOR(name))) )
             XPUSHs(HeVAL(he));
         else
             ST(0) = &PL_sv_undef;
@@ -33,7 +29,7 @@ package_name(self)
             die("Cannot call package_name as a class method");
         }
 
-        if ( (he = hv_fetch_ent((HV *)SvRV(self), key_package_name, 0, hash_package_name)) )
+        if ( (he = hv_fetch_ent((HV *)SvRV(self), KEY_FOR(package_name), 0, HASH_FOR(package_name))) )
             XPUSHs(HeVAL(he));
         else
             ST(0) = &PL_sv_undef;
@@ -48,7 +44,7 @@ body(self)
             die("Cannot call body as a class method");
         }
 
-        if ( (he = hv_fetch_ent((HV *)SvRV(self), key_body, 0, hash_body)) )
+        if ( (he = hv_fetch_ent((HV *)SvRV(self), KEY_FOR(body), 0, HASH_FOR(body))) )
             XPUSHs(HeVAL(he));
         else
             ST(0) = &PL_sv_undef;
index 9ec195c..eaac489 100644 (file)
@@ -1,7 +1,5 @@
 #include "mop.h"
 
-NEEDS_KEY(package);
-
 MODULE = Class::MOP::Package   PACKAGE = Class::MOP::Package
 
 PROTOTYPES: DISABLE
@@ -25,7 +23,7 @@ get_all_package_symbols(self, filter=TYPE_FILTER_NONE)
 
         PUTBACK;
 
-        if ( (he = hv_fetch_ent((HV *)SvRV(self), key_package, 0, hash_package)) ) {
+        if ( (he = hv_fetch_ent((HV *)SvRV(self), KEY_FOR(package), 0, HASH_FOR(package))) ) {
             stash = gv_stashsv(HeVAL(he), 0);
         }
 
@@ -47,7 +45,7 @@ name(self)
             die("Cannot call name as a class method");
         }
 
-        if ( (he = hv_fetch_ent((HV *)SvRV(self), key_package, 0, hash_package)) )
+        if ( (he = hv_fetch_ent((HV *)SvRV(self), KEY_FOR(package), 0, HASH_FOR(package))) )
             XPUSHs(HeVAL(he));
         else
             ST(0) = &PL_sv_undef;