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

Reply via email to