===================================================================
@@ -129,6 +129,14 @@ struct unw_labeled_state {
struct unw_reg_state saved_state;
};
+struct unw_alloc_context
+{
+ struct unw_reg_state *avail_reg_state;
+ struct unw_labeled_state *avail_labeled_state;
+ struct unw_reg_state **dup_state_result;
+ struct unw_reg_state *dup_state_param;
+};
+
typedef struct unw_state_record
{
unsigned int first_region : 1; /* is this the first region? */
@@ -152,9 +160,10 @@ typedef struct unw_state_record
struct unw_labeled_state *labeled_states; /* list of all labeled states */
struct unw_reg_state curr; /* current state */
+ struct unw_alloc_context ac;
_Unwind_Personality_Fn personality;
-
+
} _Unwind_FrameState;
enum unw_nat_type
@@ -237,128 +246,44 @@ static unsigned char const save_order[] =
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
-/* MASK is a bitmap describing the allocation state of emergency buffers,
- with bit set indicating free. Return >= 0 if allocation is successful;
- < 0 if failure. */
-
-static inline int
-atomic_alloc (unsigned int *mask)
-{
- unsigned int old = *mask, ret, new;
-
- while (1)
- {
- if (old == 0)
- return -1;
- ret = old & -old;
- new = old & ~ret;
- new = __sync_val_compare_and_swap (mask, old, new);
- if (old == new)
- break;
- old = new;
- }
-
- return __builtin_ffs (ret) - 1;
-}
-
-/* Similarly, free an emergency buffer. */
-
-static inline void
-atomic_free (unsigned int *mask, int bit)
-{
- __sync_xor_and_fetch (mask, 1 << bit);
-}
-
-
-#define SIZE(X) (sizeof(X) / sizeof(*(X)))
-#define MASK_FOR(X) ((2U << (SIZE (X) - 1)) - 1)
-#define PTR_IN(X, P) ((P) >= (X) && (P) < (X) + SIZE (X))
-
-static struct unw_reg_state emergency_reg_state[32];
-static unsigned int emergency_reg_state_free = MASK_FOR (emergency_reg_state);
-
-static struct unw_labeled_state emergency_labeled_state[8];
-static unsigned int emergency_labeled_state_free = MASK_FOR (emergency_labeled_state);
-
-#ifdef ENABLE_MALLOC_CHECKING
-static int reg_state_alloced;
-static int labeled_state_alloced;
-#endif
-
/* Allocation and deallocation of structures. */
static struct unw_reg_state *
-alloc_reg_state (void)
+alloc_reg_state (struct unw_alloc_context *ac)
{
struct unw_reg_state *rs;
-#ifdef ENABLE_MALLOC_CHECKING
- reg_state_alloced++;
-#endif
+ rs = ac->avail_reg_state;
+ if (rs)
+ ac->avail_reg_state = rs->next;
- rs = malloc (sizeof (struct unw_reg_state));
- if (!rs)
- {
- int n = atomic_alloc (&emergency_reg_state_free);
- if (n >= 0)
- rs = &emergency_reg_state[n];
- }
-
return rs;
}
static void
-free_reg_state (struct unw_reg_state *rs)
+free_reg_state (struct unw_reg_state *rs, struct unw_alloc_context *ac)
{
-#ifdef ENABLE_MALLOC_CHECKING
- reg_state_alloced--;
-#endif
-
- if (PTR_IN (emergency_reg_state, rs))
- atomic_free (&emergency_reg_state_free, rs - emergency_reg_state);
- else
- free (rs);
+ rs->next = ac->avail_reg_state;
+ ac->avail_reg_state = rs;
}
static struct unw_labeled_state *
-alloc_label_state (void)
+alloc_label_state (struct unw_alloc_context *ac)
{
struct unw_labeled_state *ls;
-#ifdef ENABLE_MALLOC_CHECKING
- labeled_state_alloced++;
-#endif
+ ls = ac->avail_labeled_state;
+ ac->avail_labeled_state = NULL;
- ls = malloc(sizeof(struct unw_labeled_state));
- if (!ls)
- {
- int n = atomic_alloc (&emergency_labeled_state_free);
- if (n >= 0)
- ls = &emergency_labeled_state[n];
- }
-
return ls;
}
-static void
-free_label_state (struct unw_labeled_state *ls)
-{
-#ifdef ENABLE_MALLOC_CHECKING
- labeled_state_alloced--;
-#endif
-
- if (PTR_IN (emergency_labeled_state, ls))
- atomic_free (&emergency_labeled_state_free, emergency_labeled_state - ls);
- else
- free (ls);
-}
-
/* Routines to manipulate the state stack. */
static void
push (struct unw_state_record *sr)
{
- struct unw_reg_state *rs = alloc_reg_state ();
+ struct unw_reg_state *rs = alloc_reg_state (&sr->ac);
memcpy (rs, &sr->curr, sizeof (*rs));
sr->curr.next = rs;
}
@@ -371,34 +296,40 @@ pop (struct unw_state_record *sr)
if (!rs)
abort ();
memcpy (&sr->curr, rs, sizeof(*rs));
- free_reg_state (rs);
+ free_reg_state (rs, &sr->ac);
}
/* Make a copy of the state stack. Non-recursive to avoid stack overflows. */
-static struct unw_reg_state *
-dup_state_stack (struct unw_reg_state *rs)
+static void
+dup_state_stack (struct unw_reg_state **result, struct unw_reg_state *rs,
+ struct unw_alloc_context *ac)
{
- struct unw_reg_state *copy, *prev = NULL, *first = NULL;
+ struct unw_reg_state *copy;
while (rs)
{
- copy = alloc_reg_state ();
+ copy = alloc_reg_state (ac);
+ if (!copy)
+ {
+ ac->dup_state_result = result;
+ ac->dup_state_param = rs;
+ return;
+ }
memcpy (copy, rs, sizeof(*copy));
- if (first)
- prev->next = copy;
- else
- first = copy;
+ *result = copy;
+ result = ©->next;
rs = rs->next;
- prev = copy;
}
- return first;
+ *result = NULL;
+ ac->dup_state_result = NULL;
+ ac->dup_state_param = NULL;
}
/* Free all stacked register states (but not RS itself). */
static void
-free_state_stack (struct unw_reg_state *rs)
+free_state_stack (struct unw_reg_state *rs, struct unw_alloc_context *ac)
{
struct unw_reg_state *p, *next;
@@ -405,26 +336,10 @@ static void
for (p = rs->next; p != NULL; p = next)
{
next = p->next;
- free_reg_state (p);
+ free_reg_state (p, ac);
}
rs->next = NULL;
}
-
-/* Free all labeled states. */
-
-static void
-free_label_states (struct unw_labeled_state *ls)
-{
- struct unw_labeled_state *next;
-
- for (; ls ; ls = next)
- {
- next = ls->next;
-
- free_state_stack (&ls->saved_state);
- free_label_state (ls);
- }
-}
/* Unwind decoder routines */
@@ -823,10 +738,10 @@ desc_copy_state (unw_word label, struct unw_state_
for (ls = sr->labeled_states; ls; ls = ls->next)
{
if (ls->label == label)
- {
- free_state_stack (&sr->curr);
+ {
+ free_state_stack (&sr->curr, &sr->ac);
memcpy (&sr->curr, &ls->saved_state, sizeof (sr->curr));
- sr->curr.next = dup_state_stack (ls->saved_state.next);
+ dup_state_stack (&sr->curr.next, ls->saved_state.next, &sr->ac);
return;
}
}
@@ -836,11 +751,11 @@ desc_copy_state (unw_word label, struct unw_state_
static inline void
desc_label_state (unw_word label, struct unw_state_record *sr)
{
- struct unw_labeled_state *ls = alloc_label_state ();
+ struct unw_labeled_state *ls = alloc_label_state (&sr->ac);
ls->label = label;
memcpy (&ls->saved_state, &sr->curr, sizeof (ls->saved_state));
- ls->saved_state.next = dup_state_stack (sr->curr.next);
+ dup_state_stack (&ls->saved_state.next, sr->curr.next, &sr->ac);
/* Insert into list of labeled states. */
ls->next = sr->labeled_states;
@@ -1061,7 +976,7 @@ unw_decode_uleb128 (unsigned char **dpp)
static unsigned char *
unw_decode_x1 (unsigned char *dp,
unsigned char code __attribute__((unused)),
- void *arg)
+ struct unw_state_record *arg)
{
unsigned char byte1, abreg;
unw_word t, off;
@@ -1080,7 +995,7 @@ unw_decode_x1 (unsigned char *dp,
static unsigned char *
unw_decode_x2 (unsigned char *dp,
unsigned char code __attribute__((unused)),
- void *arg)
+ struct unw_state_record *arg)
{
unsigned char byte1, byte2, abreg, x, ytreg;
unw_word t;
@@ -1100,7 +1015,7 @@ unw_decode_x2 (unsigned char *dp,
static unsigned char *
unw_decode_x3 (unsigned char *dp,
unsigned char code __attribute__((unused)),
- void *arg)
+ struct unw_state_record *arg)
{
unsigned char byte1, byte2, abreg, qp;
unw_word t, off;
@@ -1122,7 +1037,7 @@ unw_decode_x3 (unsigned char *dp,
static unsigned char *
unw_decode_x4 (unsigned char *dp,
unsigned char code __attribute__((unused)),
- void *arg)
+ struct unw_state_record *arg)
{
unsigned char byte1, byte2, byte3, qp, abreg, x, ytreg;
unw_word t;
@@ -1143,7 +1058,8 @@ unw_decode_x4 (unsigned char *dp,
}
static unsigned char *
-unw_decode_r1 (unsigned char *dp, unsigned char code, void *arg)
+unw_decode_r1 (unsigned char *dp, unsigned char code,
+ struct unw_state_record *arg)
{
int body = (code & 0x20) != 0;
unw_word rlen;
@@ -1154,7 +1070,8 @@ static unsigned char *
}
static unsigned char *
-unw_decode_r2 (unsigned char *dp, unsigned char code, void *arg)
+unw_decode_r2 (unsigned char *dp, unsigned char code,
+ struct unw_state_record *arg)
{
unsigned char byte1, mask, grsave;
unw_word rlen;
@@ -1169,7 +1086,8 @@ static unsigned char *
}
static unsigned char *
-unw_decode_r3 (unsigned char *dp, unsigned char code, void *arg)
+unw_decode_r3 (unsigned char *dp, unsigned char code,
+ struct unw_state_record *arg)
{
unw_word rlen;
@@ -1179,7 +1097,8 @@ static unsigned char *
}
static unsigned char *
-unw_decode_p1 (unsigned char *dp, unsigned char code, void *arg)
+unw_decode_p1 (unsigned char *dp, unsigned char code,
+ struct unw_state_record *arg)
{
unsigned char brmask = (code & 0x1f);
@@ -1188,7 +1107,8 @@ static unsigned char *
}
static unsigned char *
-unw_decode_p2_p5 (unsigned char *dp, unsigned char code, void *arg)
+unw_decode_p2_p5 (unsigned char *dp, unsigned char code,
+ struct unw_state_record *arg)
{
if ((code & 0x10) == 0)
{
@@ -1237,7 +1157,8 @@ static unsigned char *
}
static unsigned char *
-unw_decode_p6 (unsigned char *dp, unsigned char code, void *arg)
+unw_decode_p6 (unsigned char *dp, unsigned char code,
+ struct unw_state_record *arg)
{
int gregs = (code & 0x10) != 0;
unsigned char mask = (code & 0x0f);
@@ -1250,7 +1171,8 @@ static unsigned char *
}
static unsigned char *
-unw_decode_p7_p10 (unsigned char *dp, unsigned char code, void *arg)
+unw_decode_p7_p10 (unsigned char *dp, unsigned char code,
+ struct unw_state_record *arg)
{
unsigned char r, byte1, byte2;
unw_word t, size;
@@ -1349,7 +1271,8 @@ static unsigned char *
}
static unsigned char *
-unw_decode_b1 (unsigned char *dp, unsigned char code, void *arg)
+unw_decode_b1 (unsigned char *dp, unsigned char code,
+ struct unw_state_record *arg)
{
unw_word label = (code & 0x1f);
@@ -1361,7 +1284,8 @@ static unsigned char *
}
static unsigned char *
-unw_decode_b2 (unsigned char *dp, unsigned char code, void *arg)
+unw_decode_b2 (unsigned char *dp, unsigned char code,
+ struct unw_state_record *arg)
{
unw_word t;
@@ -1371,7 +1295,8 @@ static unsigned char *
}
static unsigned char *
-unw_decode_b3_x4 (unsigned char *dp, unsigned char code, void *arg)
+unw_decode_b3_x4 (unsigned char *dp, unsigned char code,
+ struct unw_state_record *arg)
{
unw_word t, ecount, label;
@@ -1401,7 +1326,8 @@ static unsigned char *
return dp;
}
-typedef unsigned char *(*unw_decoder) (unsigned char *, unsigned char, void *);
+typedef unsigned char *(*unw_decoder) (unsigned char *, unsigned char,
+ struct unw_state_record *arg);
static const unw_decoder unw_decode_table[2][8] =
{
@@ -1432,7 +1358,8 @@ static const unw_decoder unw_decode_table[2][8] =
* Decode one descriptor and return address of next descriptor.
*/
static inline unsigned char *
-unw_decode (unsigned char *dp, int inside_body, void *arg)
+unw_decode (unsigned char *dp, int inside_body,
+ struct unw_state_record *arg)
{
unw_decoder decoder;
unsigned char code;
@@ -1845,16 +1772,24 @@ uw_frame_state_for (struct _Unwind_Context *contex
insn = (unsigned char *) (unw + 1);
insn_end = (unsigned char *) (unw + 1 + length);
while (!fs->done && insn < insn_end)
- insn = unw_decode (insn, fs->in_body, fs);
+ {
+ if (fs->ac.avail_reg_state == NULL)
+ {
+ fs->ac.avail_reg_state = alloca (sizeof (struct unw_reg_state));
+ fs->ac.avail_reg_state->next = NULL;
+ }
+ if (fs->ac.avail_labeled_state == NULL)
+ fs->ac.avail_labeled_state = alloca (sizeof (struct unw_labeled_state));
+ insn = unw_decode (insn, fs->in_body, fs);
+ while (fs->ac.dup_state_result != NULL)
+ {
+ fs->ac.avail_reg_state = alloca (sizeof (struct unw_reg_state));
+ fs->ac.avail_reg_state->next = NULL;
+ dup_state_stack (fs->ac.dup_state_result,
+ fs->ac.dup_state_param, &fs->ac);
+ }
+ }
- free_label_states (fs->labeled_states);
- free_state_stack (&fs->curr);
-
-#ifdef ENABLE_MALLOC_CHECKING
- if (reg_state_alloced || labeled_state_alloced)
- abort ();
-#endif
-
/* If we're in the epilogue, sp has been restored and all values
on the memory stack below psp also have been restored. */
if (fs->when_target > fs->epilogue_start)