With a hint from Jonathan about storing vtable methods separately in 
namespaces and a reminder from Kevin that named lookups were still important, 
I wrestled my earlier patch into shape.

All tests pass.

I hate to brag too much about microbenchmarks, but before:

$ prove t/compilers/pge/p5regex/p5rx.t
t/compilers/pge/p5regex/p5rx....ok                                           
        355/960 skipped: various reasons
All tests successful, 355 subtests skipped.
Files=1, Tests=960,  7 wallclock secs ( 6.30 cusr +  0.20 csys =  6.50 CPU)

... after:

$ prove t/compilers/pge/p5regex/p5rx.t
t/compilers/pge/p5regex/p5rx....ok                                           
        355/960 skipped: various reasons
All tests successful, 355 subtests skipped.
Files=1, Tests=960,  2 wallclock secs ( 2.28 cusr +  0.10 csys =  2.38 CPU)

Speeding up PGE doesn't hurt my feelings.

Oh, how's Perl 6?  I'm glad you asked.  Before:

Files=27, Tests=198, 47 wallclock secs (44.69 cusr +  0.50 csys = 45.19 CPU)

... after:

Files=27, Tests=198, 11 wallclock secs ( 9.30 cusr +  0.32 csys =  9.62 CPU)

Callgrind is happier too.  Before:

2,859,808,451      452     591  PROGRAM TOTALS

370,031,493        .       .  hash.c:parrot_hash_get_idx 
296,162,666        .       .  ascii.c:ascii_compare 
216,535,642        .       .  hash.c:parrot_hash_get_bucket 
205,389,756        .       .  string.c:string_compare 
188,198,076        .       .  objects.c:find_vtable_meth_ns 
132,994,291        .       .  dod.c:Parrot_dod_sweep 
116,631,596        .       .  namespace.pmc:Parrot_NameSpace_get_pmc_keyed_str 

... after:

880,046,504      495  22,527  PROGRAM TOTALS

98,680,680        .       .  dod.c:Parrot_dod_sweep 
78,138,108        .       .  resources.c:compact_pool 
70,556,241        .       .  ascii.c:ascii_compute_hash 
49,233,260        .       .  string.c:string_make_direct 
41,103,096        .       .  headers.c:get_free_buffer 
30,652,923        .       .  resources.c:Parrot_allocate_string 

I do think there are still some cleanups in this area, but getting a three to 
five time speedup *without breaking any tests* as well as simplifying some a 
grotty code seems like a good thing to me.

-- c
=== compilers/imcc/pbc.c
==================================================================
--- compilers/imcc/pbc.c	(revision 4018)
+++ compilers/imcc/pbc.c	(local)
@@ -782,8 +782,6 @@
     else
         sub->multi_signature = NULL;
 
-    Parrot_store_sub_in_namespace(interp, sub_pmc);
-
     if (unit->is_vtable_method == 1) {
         /* Work out the name of the vtable method. */
         if (unit->vtable_name != NULL)
@@ -808,6 +806,8 @@
         sub->vtable_index = vtable_index;
     }
 
+    Parrot_store_sub_in_namespace(interp, sub_pmc);
+
     pfc->type     = PFC_PMC;
     pfc->u.key    = sub_pmc;
     unit->sub_pmc = sub_pmc;
=== src/objects.c
==================================================================
--- src/objects.c	(revision 4018)
+++ src/objects.c	(local)
@@ -81,28 +81,7 @@
 static PMC*
 find_vtable_meth_ns(Interp *interp, PMC *ns, INTVAL vtable_index)
 {
-    const INTVAL k   = VTABLE_elements(interp, ns);
-    PMC   * const key = VTABLE_nextkey_keyed(interp, key_new(interp), ns,
-        ITERATE_FROM_START);
-
-    const char * const meth     = Parrot_vtable_slot_names[vtable_index];
-    STRING     * const meth_str = string_from_cstring(interp, meth, strlen(meth));
-
-    int         j;
-
-    for (j = 0; j < k; ++j) {
-        STRING * const ns_key = (STRING *)parrot_hash_get_idx(interp,
-                            (Hash *)PMC_struct_val(ns), key);
-        PMC * const res    = VTABLE_get_pmc_keyed_str(interp, ns, ns_key);
-
-        /* success if matching vtable index or double-underscored name */
-        if (res->vtable->base_type == enum_class_Sub &&
-               (PMC_sub(res)->vtable_index == vtable_index ||
-                string_compare(interp, meth_str, ns_key) == 0))
-            return res;
-    }
-
-    return PMCNULL;
+    return VTABLE_get_pmc_keyed_int(interp, ns, vtable_index);
 }
 
 /*
=== src/pmc/namespace.pmc
==================================================================
--- src/pmc/namespace.pmc	(revision 4018)
+++ src/pmc/namespace.pmc	(local)
@@ -1,5 +1,5 @@
 /*
-Copyright (C) 2005, The Perl Foundation.
+Copyright (C) 2005-2007, The Perl Foundation.
 $Id$
 
 =head1 NAME
@@ -12,8 +12,8 @@
 
 =head2 Data
 
-  PMC_struct_val       ... the hash, bucket->value is either a
-                           var/sub or a namespace, of a FixedPMCarray
+  PMC_struct_val       ... the hash, bucket->value is a
+                           var/sub, a namespace, or a FixedPMCarray
                            of 2 PMCs (namespace, sub/var) slots
   PMC_pmc_val          ... parent namespace
   PMC_data             ... Namespace information struct (name, class/role)
@@ -30,14 +30,14 @@
 #include <assert.h>
 
 /*
- * Typically a named slot either contains another namespace or a
+ * Typically a named slot contains either another namespace or a
  * var/sub (not both).
  * In case that the bucket->value is occupied, a FixedPMCArray is
  * created, and the items are moved over to that extra storage.
  * The array is flagged with FPA_is_ns_ext to distinguish it from a
  * plain array variable.
  *
- * This could easily expanded to a full-fledged typed namespace if needed.
+ * This could easily expand to a full-fledged typed namespace if needed.
  */
 
 enum {
@@ -52,11 +52,12 @@
 /* We store extra information about the namespace in a struct, which we will
  * hang off the PMC_data slot. */
 typedef struct Parrot_NSInfo {
-    STRING *name;  /* Name of this namespace part. */
-    PMC *_class;   /* The class or role attached to this namespace. */
+    STRING *name;     /* Name of this namespace part. */
+    PMC    *_class;   /* The class or role attached to this namespace. */
+    PMC    *vtable;
 } Parrot_NSInfo;
 
-/* Macro for easy access to the namespcae info. */
+/* Macro for easy access to the namespace info. */
 #define PARROT_NSINFO(o) ((Parrot_NSInfo *) PMC_data(o))
 
 
@@ -74,9 +75,10 @@
 */
 
     void init() {
-        SUPER();                        /* _struct_val := Hash */
-        PMC_pmc_val(SELF) = NULL;       /* parent */
-        PMC_data(SELF)    = mem_allocate_zeroed_typed(Parrot_NSInfo);
+        SUPER();                             /* _struct_val := Hash */
+        PMC_pmc_val(SELF)           = NULL;  /* parent */
+        PMC_data(SELF)              = mem_allocate_zeroed_typed(Parrot_NSInfo);
+        PARROT_NSINFO(SELF)->vtable = PMCNULL;
     }
 
 /*
@@ -97,6 +99,8 @@
             pobject_lives(INTERP, (PObj*)nsinfo->name);
         if (nsinfo->_class)
             pobject_lives(INTERP, (PObj*)nsinfo->_class);
+        if (nsinfo->vtable)
+            pobject_lives(INTERP, (PObj*)nsinfo->vtable);
     }
 
 /*
@@ -132,7 +136,7 @@
 Return the given namespace or PMCNULL. C<key> is either an array of
 strings, or a possibly nested key.
 
-=item C<PMC* get_pmc_keyed_str(PMC *key)>
+=item C<PMC* get_pmc_keyed_str(STRING *key)>
 
 Return the given namespace item or PMCNULL. If the named item is either
 a NameSpace or a var, the NameSpace is returned.
@@ -198,6 +202,31 @@
             VTABLE_set_pmc_keyed_int(INTERP, new_tuple, NS_slot_var_sub, value);
             b->value = new_tuple;
         }
+
+        if (value->vtable->base_type == enum_class_Sub) {
+            Parrot_NSInfo *nsinfo    = PARROT_NSINFO(SELF);
+            PMC           *vtable    = nsinfo->vtable;
+            Parrot_sub    *sub       = PMC_sub(value);
+
+            if (PMC_IS_NULL(vtable))
+                nsinfo->vtable = vtable = pmc_new(interp, enum_class_Hash);
+
+            if (sub->vtable_index == -1) {
+                STRING *meth_name = key;
+
+                if (string_str_index(interp, key,
+                    CONST_STRING(interp, "__"), 0 == 0)) {
+                    meth_name = string_substr(interp, key, 2,
+                        string_length(interp, key) - 2, NULL, 0);
+                }
+
+                sub->vtable_index = Parrot_get_vtable_index(interp, meth_name);
+            }
+
+            if (sub->vtable_index != -1)
+                VTABLE_set_pmc_keyed_int(INTERP, vtable,
+                    sub->vtable_index, value);
+        }
     }
 
     void set_pmc_keyed(PMC *key, PMC *value) {
@@ -263,6 +292,16 @@
         return PMCNULL;
     }
 
+    PMC* get_pmc_keyed_int(INTVAL key) {
+        Parrot_NSInfo *nsinfo = PARROT_NSINFO(SELF);
+        PMC           *vtable = nsinfo->vtable;
+
+        if (PMC_IS_NULL(vtable))
+            return PMCNULL;
+
+        return VTABLE_get_pmc_keyed_int(interp, vtable, key);
+    }
+
 /*
 
 =item C<void* get_pointer_keyed_str(STRING *key)>

Reply via email to