# New Ticket Created by Nick Glencross
# Please include the string: [perl #59546]
# in the subject line of all future correspondence about this issue.
# <URL: http://rt.perl.org/rt3/Ticket/Display.html?id=59546 >
Hi All,
This patch adds two new opcodes which allow a hash "exists" and "get"
to be performed together, which we can use in the OO subsystem to
achieve a (roughly) 5% performance improvement (tested on the perl6
build and november).
A 'make realclean' appears to be needed after applying the patch.
Regards,
Nick
Patch which combines hash "exists" and "get" calls into a new op code
internally, giving a 5% performance increase on some
real-world code.
Index: src/vtable.tbl
===================================================================
--- src/vtable.tbl (revision 31552)
+++ src/vtable.tbl (working copy)
@@ -61,6 +61,10 @@
PMC* get_pmc_keyed_str(STRING* key)
PMC* slice(PMC* key, INTVAL flag)
+# These variants perform exists/get in a single operation for efficiency
+INTVAL get_integer_keyed_str_exists(STRING* key, INTVAL* exists)
+PMC* get_pmc_keyed_str_exists(STRING* key, INTVAL* exists)
+
void* get_pointer()
void* get_pointer_keyed(PMC* key)
void* get_pointer_keyed_int(INTVAL key)
Index: src/oo.c
===================================================================
--- src/oo.c (revision 31552)
+++ src/oo.c (working copy)
@@ -331,14 +331,18 @@
{
Parrot_Class_attributes * const _class = PARROT_CLASS(classobj);
- if (VTABLE_exists_keyed_str(interp, _class->parent_overrides, name))
- return VTABLE_get_pmc_keyed_str(interp, _class->parent_overrides, name);
- else {
+ INTVAL exists;
+
+ PMC* result = VTABLE_get_pmc_keyed_str_exists(interp,
+ _class->parent_overrides, name, &exists);
+
+ if (!exists) {
/* Walk and search for the vtable method. */
const INTVAL num_classes = VTABLE_elements(interp, _class->all_parents);
- PMC *result = PMCNULL;
INTVAL i;
+ result = PMCNULL;
+
for (i = 0; i < num_classes; i++) {
/* Get the class. */
PMC * const cur_class =
@@ -352,9 +356,10 @@
}
VTABLE_set_pmc_keyed_str(interp, _class->parent_overrides, name, result);
+ }
- return result;
- }
+
+ return result;
}
@@ -1301,7 +1306,7 @@
"A conflict occurred during role composition "
"due to method '%S'.", method_name);
- /* What about a conflict with ourslef? */
+ /* What about a conflict with ourself? */
if (VTABLE_exists_keyed_str(interp, proposed_add_methods,
method_name))
/* Something very weird is going on. */
Index: src/pmc/object.pmc
===================================================================
--- src/pmc/object.pmc (revision 31552)
+++ src/pmc/object.pmc (working copy)
@@ -31,12 +31,16 @@
INTVAL cur_hll = CONTEXT(interp)->current_HLL;
int num_classes, i;
+ INTVAL exists, retval;
+
CONTEXT(interp)->current_HLL = 0;
/* First see if we can find it in the cache. */
- if (VTABLE_exists_keyed_str(interp, _class->attrib_cache, name)) {
- INTVAL retval =
- VTABLE_get_integer_keyed_str(interp, _class->attrib_cache, name);
+ retval =
+ VTABLE_get_integer_keyed_str_exists(interp, _class->attrib_cache, name,
+ &exists);
+
+ if (exists) {
CONTEXT(interp)->current_HLL = cur_hll;
return retval;
}
@@ -46,6 +50,8 @@
num_classes = VTABLE_elements(interp, _class->all_parents);
for (i = 0; i < num_classes; i++) {
+ INTVAL index;
+
/* Get the class and its attribute metadata hash. */
PMC * const cur_class = VTABLE_get_pmc_keyed_int(interp,
_class->all_parents, i);
@@ -55,10 +61,11 @@
fq_name = string_append(interp, fq_name, name);
/* Look up. */
- if (VTABLE_exists_keyed_str(interp, _class->attrib_index, fq_name)) {
- /* Found it. Get value, cache it and we're done. */
- const INTVAL index = VTABLE_get_integer_keyed_str(interp,
- _class->attrib_index, fq_name);
+ index = VTABLE_get_integer_keyed_str_exists(interp,
+ _class->attrib_index, fq_name, &exists);
+
+ if (exists) {
+ /* Found it. Cache value and we're done. */
VTABLE_set_integer_keyed_str(interp, _class->attrib_cache, name,
index);
@@ -83,6 +90,8 @@
_class->attrib_cache, VTABLE_get_string(interp, key));
PMC *parent_class;
STRING *fq_name;
+ INTVAL exists;
+ int index;
if (!PMC_IS_NULL(class_cache))
if (VTABLE_exists_keyed_str(interp, class_cache, name))
@@ -334,6 +343,7 @@
int alien_parents_pos = VTABLE_elements(interp,
_class->attrib_metadata);
int i;
+ INTVAL exists;
for (i = 0; i < num_classes; i++) {
/* Get the class. */
@@ -353,10 +363,14 @@
* anything outside of it... */
if (all_in_universe || VTABLE_isa(interp, cur_class, CONST_STRING(interp, "Class"))) {
const Parrot_Class_attributes * const class_info = PARROT_CLASS(cur_class);
- if (VTABLE_exists_keyed_str(interp, class_info->methods, name)) {
- /* Found it! */
- method = VTABLE_get_pmc_keyed_str(interp, class_info->methods, name);
- break;
+ PMC* m = VTABLE_get_pmc_keyed_str_exists(interp,
+ class_info->methods, name, &exists);
+
+ if (exists)
+ {
+ /* Found it! */
+ method = m;
+ break;
}
}
else {
Index: src/pmc/hash.pmc
===================================================================
--- src/pmc/hash.pmc (revision 31552)
+++ src/pmc/hash.pmc (working copy)
@@ -304,6 +304,47 @@
/*
+=item C<INTVAL get_integer_keyed_str_exists(STRING *key, INTVAL* exists)>
+
+=item C<PMC *get_pmc_keyed_str_exists(STRING *key, INTVAL* exists)>
+
+As well as returning a value, also sets the C<exists> flag making it
+possible to determine if the key exists.
+
+=cut
+
+*/
+
+ VTABLE INTVAL get_integer_keyed_str_exists(STRING *key, INTVAL* exists) {
+ HashBucket * const b =
+ parrot_hash_get_bucket(INTERP, (Hash *)PMC_struct_val(SELF), key);
+
+ if (exists)
+ *exists = (b != NULL);
+
+ if (!b)
+ return 0;
+
+ return VTABLE_get_integer(INTERP, (PMC*) b->value);
+ }
+
+
+ VTABLE PMC *get_pmc_keyed_str_exists(STRING *key, INTVAL* exists) {
+ HashBucket * const b =
+ parrot_hash_get_bucket(INTERP, (Hash*) PMC_struct_val(SELF), key);
+
+ if (exists)
+ *exists = (b != NULL);
+
+ if (!b)
+ return PMCNULL;
+
+ return (PMC *)b->value;
+ }
+
+
+/*
+
=item C<FLOATVAL get_number()>
Returns the size of the hash.
@@ -558,6 +599,7 @@
return (PMC *)b->value;
}
+
VTABLE PMC *get_pmc_keyed_int(INTVAL key) {
STRING * const s = string_from_int(INTERP, key);
return SELF.get_pmc_keyed_str(s);