We can speed up PGE by 40%, if not more, by removing the great hate that is
Parrot_get_vtable_index(), which performs a binary search of all of the
vtable names with a strcmp for each one. This function gets called every
time something wonders "Hey, am I about to call a vtable entry?"
That happens a lot.
Instead, I prefer to store the vtable entries in the appropriate namespace
*when they get added to the namespace*. Okay, we already do that... but we
first resolve the name to the entry index number, then store the Sub PMC in
the cache indexed off of the number.
That's all well and good, but it means that whenever we want to look up an
entry, we take the name (yes, we look them up pretty much all the time by
name, why are you looking at me funny), perform the binary search with all of
the strcmps, find the index, then look in the cache.
I managed to get this to work in a really ugly way that I don't want to talk
about in order to prove that the speed gain really was about 40%. Here's a
cleaner patch that respects actual encapsulation.
Unfortunately, I don't have the hang of calling methods (real methods, not
vtable entries) on PMCs from C yet, so it's fast... on the way to segfault
town, riding the SIGBUS. Jonathan?
-- c
=== src/objects.c
==================================================================
--- src/objects.c (revision 4835)
+++ src/objects.c (local)
@@ -204,12 +204,6 @@
PMC *ns, *mro;
PMC *_class = pmc;
- /* Get index in Parrot_vtable_slot_names[]. */
- const INTVAL vtable_index = Parrot_get_vtable_index(interp, meth);
-
- if (vtable_index == -1)
- return PMCNULL;
-
/* Get class. */
if (PObj_is_object_TEST(pmc))
_class = GET_CLASS(PMC_data_typed(pmc, Buffer), pmc);
@@ -224,7 +218,8 @@
ns = VTABLE_pmc_namespace(interp, _class);
if (!PMC_IS_NULL(ns)) {
- PMC * const res = find_vtable_meth_ns(interp, ns, vtable_index);
+ PMC * const res = Parrot_call_method(interp, PMCNULL, ns,
+ string_from_literal(interp, "get_vtable_entry"), "P->S", meth);
if (!PMC_IS_NULL(res))
return res;
=== src/pmc/namespace.pmc
==================================================================
--- src/pmc/namespace.pmc (revision 4847)
+++ src/pmc/namespace.pmc (local)
@@ -54,7 +54,7 @@
typedef struct Parrot_NSInfo {
STRING *name; /* Name of this namespace part. */
PMC *_class; /* The class or role attached to this namespace. */
- PMC *vtable; /* A Hash of vtable subs, keyed on the vtable index */
+ PMC *vtable; /* A Hash of vtable subs, keyed on the vtable name */
} Parrot_NSInfo;
/* Macro for easy access to the namespace info. */
@@ -229,25 +229,22 @@
Parrot_NSInfo *nsinfo = PARROT_NSINFO(SELF);
PMC *vtable = nsinfo->vtable;
Parrot_sub *sub = PMC_sub(value);
+ STRING *meth_name = key;
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);
- 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);
- }
+ if (sub->vtable_index == -1)
+ sub->vtable_index = Parrot_get_vtable_index(interp, meth_name);
- sub->vtable_index = Parrot_get_vtable_index(interp, meth_name);
+ if (sub->vtable_index != -1)
+ VTABLE_set_pmc_keyed_str(INTERP, vtable, key, meth_name);
}
-
- if (sub->vtable_index != -1)
- VTABLE_set_pmc_keyed_int(INTERP, vtable,
- sub->vtable_index, value);
}
}
@@ -318,6 +315,7 @@
Parrot_NSInfo *nsinfo = PARROT_NSINFO(SELF);
PMC *vtable = nsinfo->vtable;
+ assert(0);
if (PMC_IS_NULL(vtable))
return PMCNULL;
@@ -415,6 +413,8 @@
Stores the given namespace under this namespace, with the given name. Throws
an invalid type exception if C<namespace> is not a NameSpace PMC or subclass.
+=cut
+
*/
METHOD void add_namespace(STRING *name, PMC *_namespace) {
@@ -437,6 +437,8 @@
Stores the given sub under this namespace, with the given name. Throws an
invalid type exception if C<sub> is not a Sub PMC or subclass.
+=cut
+
*/
METHOD void add_sub(STRING *name, PMC *sub) {
@@ -449,14 +451,24 @@
return;
}
-/*
+ PCCMETHOD void get_vtable_entry(STRING *name) {
+ PMC *entries = PARROT_NSINFO(SELF)->vtable;
+ PMC *entry = PMCNULL;
+ if (!PMC_IS_NULL(entries))
+ entry = VTABLE_get_pmc_keyed_str(INTERP, entries, name);
+
+ PCCRETURN(PMC *entry);
+ }
+
/*
=item C<METHOD void PMC* add_var(STRING *name, PMC *var)>
Stores the given sub under this namespace, with the given name.
+=cut
+
*/
METHOD void add_var(STRING *name, PMC *var) {