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)>