summaryrefslogtreecommitdiff
path: root/libdw
diff options
context:
space:
mode:
authorJosh Stone <jistone@redhat.com>2013-12-09 13:52:10 -0800
committerJosh Stone <jistone@redhat.com>2013-12-13 09:48:07 -0800
commitc0d2a0b3a38bfb5164c1cf822d50e46cfad9c071 (patch)
treeec3c255fa5962f3bcc8cebb22df04776b8af8a0f /libdw
parent3951f2ec0aaca021c77a2c7a464dcf43433261c3 (diff)
downloadelfutils-c0d2a0b3a38bfb5164c1cf822d50e46cfad9c071.tar.gz
libdw: 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>
Diffstat (limited to 'libdw')
-rw-r--r--libdw/ChangeLog6
-rw-r--r--libdw/libdwP.h36
-rw-r--r--libdw/libdw_form.c32
3 files changed, 43 insertions, 31 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 79bb4b57..a2e4b142 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 35ab6e79..49392005 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,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;
diff --git a/libdw/libdw_form.c b/libdw/libdw_form.c
index c476a6e3..53505564 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;