]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
libdw: Add an inlined fast path for __libdw_form_val_len
authorJosh Stone <jistone@redhat.com>
Mon, 9 Dec 2013 21:52:10 +0000 (13:52 -0800)
committerJosh Stone <jistone@redhat.com>
Fri, 13 Dec 2013 17:48:07 +0000 (09:48 -0800)
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
libdw/libdwP.h
libdw/libdw_form.c

index 79bb4b57fc4a50e8b1467ee507b884853e5c6d30..a2e4b142a107ce2c8733446e548148239638d97a 100644 (file)
@@ -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
index 35ab6e79c3fa2d5c45061fe12cce95121e475691..4939200501011bdbcda3bac37023f1c3174657c7 100644 (file)
@@ -34,6 +34,7 @@
 #include <stdbool.h>
 
 #include <libdw.h>
+#include <dwarf.h>
 
 
 /* gettext helper macros.  */
@@ -403,11 +404,40 @@ 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.  Absent indexes are
+     initialized 0, so any truly desired 0 is set to 0x80 and masked.  */
+  static const uint8_t form_lengths[] =
+    {
+      [DW_FORM_flag_present] = 0x80,
+      [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,
+    };
+
+  /* Return immediately for forms with fixed lengths.  */
+  if (form < sizeof form_lengths / sizeof form_lengths[0])
+    {
+      uint8_t len = form_lengths[form];
+      if (len != 0)
+       return len & 0x7f; /* Mask to allow 0x80 -> 0.  */
+    }
+
+  /* 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;
index c476a6e31f3225c022cc51d499ff807638673a79..53505564d699c9fbb397605ea93f223402cd9684 100644 (file)
 
 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;