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