This is the mail archive of the elfutils-devel@sourceware.org mailing list for the elfutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 1/3] Add an inlined fast path for __libdw_form_val_len


Quite a few DW_FORMs have a fixed length for their data, and we can
easily represent these in a small lookup table.  The rest of the forms
are left in the old function to compute as needed.  Combined with
inlining, this takes care of many forms with fewer branches and without
any call.  (It's conceivable that a smart compiler could make a similar
lookup transformation from the large switch itself, but GCC doesn't.)

Signed-off-by: Josh Stone <jistone@redhat.com>
---
 libdw/ChangeLog    |  6 ++++++
 libdw/libdwP.h     | 39 ++++++++++++++++++++++++++++++++++++---
 libdw/libdw_form.c | 32 ++++----------------------------
 3 files changed, 46 insertions(+), 31 deletions(-)

diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 79bb4b57fc4a..a2e4b142a107 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,9 @@
+2013-12-09  Josh Stone  <jistone@redhat.com>
+
+	* libdw_form.c (__libdw_form_val_compute_len): Renamed function from
+	__libdw_form_val_len, now handling only non-constant form lengths.
+	* libdwP.h (__libdw_form_val_len): New inlined function.
+
 2013-12-09  Mark Wielaard  <mjw@redhat.com>
 
 	* dwarf_getlocation.c (__libdw_intern_expression): Handle empty
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index 35ab6e79c3fa..bd668c710029 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -34,6 +34,7 @@
 #include <stdbool.h>
 
 #include <libdw.h>
+#include <dwarf.h>
 
 
 /* gettext helper macros.  */
@@ -403,11 +404,43 @@ extern Dwarf_Abbrev *__libdw_getabbrev (Dwarf *dbg, struct Dwarf_CU *cu,
      __nonnull_attribute__ (1) internal_function;
 
 /* Helper functions for form handling.  */
-extern size_t __libdw_form_val_len (Dwarf *dbg, struct Dwarf_CU *cu,
-				    unsigned int form,
-				    const unsigned char *valp)
+extern size_t __libdw_form_val_compute_len (Dwarf *dbg, struct Dwarf_CU *cu,
+					    unsigned int form,
+					    const unsigned char *valp)
      __nonnull_attribute__ (1, 2, 4) internal_function;
 
+/* Find the length of a form attribute.  */
+static inline size_t
+__nonnull_attribute__ (1, 2, 4)
+__libdw_form_val_len (Dwarf *dbg, struct Dwarf_CU *cu,
+		      unsigned int form, const unsigned char *valp)
+{
+  /* Small lookup table of forms with fixed lengths.  */
+  static const uint8_t form_lengths[] =
+    {
+      [DW_FORM_data1] = 1, [DW_FORM_ref1] = 1, [DW_FORM_flag] = 1,
+      [DW_FORM_data2] = 2, [DW_FORM_ref2] = 2,
+      [DW_FORM_data4] = 4, [DW_FORM_ref4] = 4,
+      [DW_FORM_data8] = 8, [DW_FORM_ref8] = 8, [DW_FORM_ref_sig8] = 8,
+    };
+
+  /* Note that form_lengths[flag_present] is 0, like every other absent index.
+   * But since flag_present's length truly is 0, check for it explicitly.  */
+  if (form == DW_FORM_flag_present)
+    return 0;
+
+  /* Return immediately for forms with fixed lengths.  */
+  if (form < sizeof(form_lengths) / sizeof(form_lengths[0]))
+    {
+      size_t len = form_lengths[form];
+      if (len != 0)
+	return len;
+    }
+
+  /* Other forms require some computation.  */
+  return __libdw_form_val_compute_len (dbg, cu, form, valp);
+}
+
 /* Helper function for DW_FORM_ref* handling.  */
 extern int __libdw_formref (Dwarf_Attribute *attr, Dwarf_Off *return_offset)
      __nonnull_attribute__ (1, 2) internal_function;
diff --git a/libdw/libdw_form.c b/libdw/libdw_form.c
index c476a6e31f32..cf8e4d854fcb 100644
--- a/libdw/libdw_form.c
+++ b/libdw/libdw_form.c
@@ -39,13 +39,15 @@
 
 size_t
 internal_function
-__libdw_form_val_len (Dwarf *dbg, struct Dwarf_CU *cu, unsigned int form,
-		      const unsigned char *valp)
+__libdw_form_val_compute_len (Dwarf *dbg, struct Dwarf_CU *cu,
+			      unsigned int form, const unsigned char *valp)
 {
   const unsigned char *saved;
   Dwarf_Word u128;
   size_t result;
 
+  /* NB: This doesn't cover constant form lengths, which are
+   * already handled by the inlined __libdw_form_val_len.  */
   switch (form)
     {
     case DW_FORM_addr:
@@ -82,32 +84,6 @@ __libdw_form_val_len (Dwarf *dbg, struct Dwarf_CU *cu, unsigned int form,
       result = u128 + (valp - saved);
       break;
 
-    case DW_FORM_flag_present:
-      result = 0;
-      break;
-
-    case DW_FORM_ref1:
-    case DW_FORM_data1:
-    case DW_FORM_flag:
-      result = 1;
-      break;
-
-    case DW_FORM_data2:
-    case DW_FORM_ref2:
-      result = 2;
-      break;
-
-    case DW_FORM_data4:
-    case DW_FORM_ref4:
-      result = 4;
-      break;
-
-    case DW_FORM_data8:
-    case DW_FORM_ref8:
-    case DW_FORM_ref_sig8:
-      result = 8;
-      break;
-
     case DW_FORM_string:
       result = strlen ((char *) valp) + 1;
       break;
-- 
1.8.4.2


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]