From 7bb65377a5e147a86631f704848dbaf8f1db8e9a Mon Sep 17 00:00:00 2001 From: Dodji Seketeli Date: Thu, 15 Oct 2015 10:50:36 +0200 Subject: [PATCH] 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 --- include/abg-ir.h | 12 +++++++++ src/abg-ir.cc | 69 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/include/abg-ir.h b/include/abg-ir.h index bebbd25a..412536d8 100644 --- a/include/abg-ir.h +++ b/include/abg-ir.h @@ -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 diff --git a/src/abg-ir.cc b/src/abg-ir.cc index 4a693ff1..2f54b6c8 100644 --- a/src/abg-ir.cc +++ b/src/abg-ir.cc @@ -4794,6 +4794,29 @@ function_decl_sptr is_function_decl(decl_base_sptr d) {return dynamic_pointer_cast(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 + (const_cast(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(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(*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 + (const_cast(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(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 hash_bool; + std::tr1::hash 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 hash_size; + std::tr1::hash 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