Accelerate a slow path in hash_type_or_decl()

Profiling shows that hash_type_or_decl() is very slow when hashing
function parameters and base class specifications.  This is because in
those two cases we use the slow recursive hashing algorithm to hash
types, rather than using the faster one based on using the pointer
values of canonical types when possible.

This was making corpora comparison very slow, as it uses
hash_type_or_decl() to hash diffs of ABI artifacts.

This patch fixes that.

	* include/abg-ir.h (is_function_parameter, is_class_base_spec):
	Declare new functions.
	* src/abg-ir.cc (is_function_parameter, is_class_base_spec):
	Define them.
	(hash_type_or_decl): Handle hashing of function parameters are
	class base specifications with the fast path of type hashing.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
This commit is contained in:
Dodji Seketeli 2015-10-15 10:50:36 +02:00
parent 60425d2996
commit 7bb65377a5
2 changed files with 81 additions and 0 deletions

View File

@ -2258,6 +2258,12 @@ struct function_decl::parameter::hash
operator()(const function_decl::parameter_sptr) const;
}; // end struct function_decl::parameter::hash
function_decl::parameter*
is_function_parameter(const type_or_decl_base*);
function_decl::parameter_sptr
is_function_parameter(const type_or_decl_base_sptr tod);
bool
equals(const function_type&, const function_type&, change_kind*);
@ -3090,6 +3096,12 @@ bool
operator==(const class_decl::base_spec_sptr l,
const class_decl::base_spec_sptr r);
class_decl::base_spec*
is_class_base_spec(type_or_decl_base*);
class_decl::base_spec_sptr
is_class_base_spec(type_or_decl_base_sptr);
class mem_fn_context_rel;
/// A convenience typedef for a shared pointer to @ref

View File

@ -4794,6 +4794,29 @@ function_decl_sptr
is_function_decl(decl_base_sptr d)
{return dynamic_pointer_cast<function_decl>(d);}
/// Test whether a declaration is a @ref function_decl.
///
/// @param d the declaration to test for.
///
/// @return a pointer to @ref function_decl if @p d is a @ref
/// function_decl. Otherwise, a nil shared pointer.
function_decl::parameter*
is_function_parameter(const type_or_decl_base* tod)
{
return dynamic_cast<function_decl::parameter*>
(const_cast<type_or_decl_base*>(tod));
}
/// Test whether an ABI artifact is a @ref function_decl.
///
/// @param tod the declaration to test for.
///
/// @return a pointer to @ref function_decl if @p d is a @ref
/// function_decl. Otherwise, a nil shared pointer.
function_decl::parameter_sptr
is_function_parameter(const type_or_decl_base_sptr tod)
{return dynamic_pointer_cast<function_decl::parameter>(tod);}
/// Test if an ABI artifact is a declaration.
///
/// @param d the artifact to consider.
@ -11723,6 +11746,29 @@ operator==(const class_decl::base_spec_sptr l,
return *l == static_cast<const decl_base&>(*r);
}
/// Test if an ABI artifact is a class base specifier.
///
/// @param tod the ABI artifact to consider.
///
/// @return a pointer to the @ref class_decl::base_spec sub-object of
/// @p tod iff it's a class base specifier.
class_decl::base_spec*
is_class_base_spec(const type_or_decl_base* tod)
{
return dynamic_cast<class_decl::base_spec*>
(const_cast<type_or_decl_base*>(tod));
}
/// Test if an ABI artifact is a class base specifier.
///
/// @param tod the ABI artifact to consider.
///
/// @return a pointer to the @ref class_decl::base_spec sub-object of
/// @p tod iff it's a class base specifier.
class_decl::base_spec_sptr
is_class_base_spec(type_or_decl_base_sptr tod)
{return dynamic_pointer_cast<class_decl::base_spec>(tod);}
bool
class_decl::member_function_template::operator==(const member_base& other) const
{
@ -12925,6 +12971,29 @@ hash_type_or_decl(const type_or_decl_base *tod)
h = hashing::combine_hashes(h, hash_string(repr));
result = h;
}
else if (function_decl::parameter* p = is_function_parameter(d))
{
type_base_sptr parm_type = p->get_type();
assert(parm_type);
std::tr1::hash<bool> hash_bool;
std::tr1::hash<unsigned> hash_unsigned;
size_t h = hash_type_or_decl(parm_type);
h = hashing::combine_hashes(h, hash_unsigned(p->get_index()));
h = hashing::combine_hashes(h, hash_bool(p->get_variadic_marker()));
result = h;
}
else if (class_decl::base_spec *bs = is_class_base_spec(d))
{
class_decl::member_base::hash hash_member;
std::tr1::hash<size_t> hash_size;
std::tr1::hash<bool> hash_bool;
type_base_sptr type = bs->get_base_class();
size_t h = hash_type_or_decl(type);
h = hashing::combine_hashes(h, hash_member(*bs));
h = hashing::combine_hashes(h, hash_size(bs->get_offset_in_bits()));
h = hashing::combine_hashes(h, hash_bool(bs->get_is_virtual()));
result = h;
}
else
// This is a *really* *SLOW* path. If it shows up in a
// performan profile, I bet it'd be a good idea to try to