#include "hashtab.h"
#ifndef IGNORE_LOCUS
-#define IGNORE_LOCUS 0
+# define IGNORE_LOCUS 0
#endif
#define obstack_chunk_alloc xmalloc
/* General obstack for struct dw_cu, dw_die, also used for temporary
vectors. */
static struct obstack ob;
+/* Short lived obstack, global only to free it on allocation failures. */
+static struct obstack alt_ob;
typedef struct
{
#define die_safe_nextdup(die) \
((die)->die_toplevel ? (die)->die_nextdup : (dw_die_ref) NULL)
+#ifdef __GNUC__
+# define ALIGN_STRUCT(name)
+#else
+# define ALIGN_STRUCT(name) struct align_##name { char c; struct name s; };
+#endif
+ALIGN_STRUCT (abbrev_tag)
+ALIGN_STRUCT (dw_file)
+ALIGN_STRUCT (dw_cu)
+ALIGN_STRUCT (dw_die)
+
+/* Big pool allocator. obstack isn't efficient, because it aligns everything
+ too much, and allocates too small chunks. All these objects are only freed
+ together. */
+
+static unsigned char *pool, *pool_next, *pool_limit;
+
+static void *
+pool_alloc_1 (unsigned int align, unsigned int size)
+{
+ void *ret;
+ if (pool == NULL
+ || (size_t) (pool_limit - pool_next) < (size_t) align + size)
+ {
+ size_t new_size = (size_t) align + size;
+ unsigned char *new_pool;
+ new_size += sizeof (void *);
+ if (new_size < 16384 * 1024 - 64)
+ new_size = 16384 * 1024 - 64;
+ new_pool = (unsigned char *) xmalloc (new_size);
+ *(unsigned char **) new_pool = pool;
+ pool_next = new_pool + sizeof (unsigned char *);
+ pool_limit = new_pool + new_size;
+ pool = new_pool;
+ }
+ pool_next = (unsigned char *) (((uintptr_t) pool_next + align - 1)
+ & ~(uintptr_t) (align - 1));
+ ret = pool_next;
+ pool_next += size;
+ return ret;
+}
+
+static void
+pool_destroy (void)
+{
+ pool_next = NULL;
+ pool_limit = NULL;
+ while (pool)
+ {
+ void *p = (void *) pool;
+ pool = *(unsigned char **) pool;
+ free (p);
+ }
+}
+
+#ifdef __GNUC__
+# define pool_alloc(name, size) \
+ (struct name *) pool_alloc_1 (__alignof__ (struct name), size)
+#else
+# define pool_alloc(name, size) \
+ (struct name *) pool_alloc_1 (offsetof (struct align_##name, s), size)
+#endif
+
/* Hash function in first abbrev hash table as well as cu->cu_new_abbrev
htab. */
static hashval_t
return NULL;
}
- t = (struct abbrev_tag *)
- obstack_alloc (&ob,
- sizeof (*t) + nattr * sizeof (struct abbrev_attr));
+ t = pool_alloc (abbrev_tag,
+ sizeof (*t) + nattr * sizeof (struct abbrev_attr));
t->entry = attr;
t->hash = attr;
t->nattr = 0;
}
cu->cu_nfiles = file_cnt;
- cu->cu_files = (struct dw_file *)
- obstack_alloc (&ob, file_cnt * sizeof (struct dw_file));
+ cu->cu_files = pool_alloc (dw_file, file_cnt * sizeof (struct dw_file));
memset (cu->cu_files, 0, file_cnt * sizeof (struct dw_file));
ptr = file;
is owned by more than one CU. */
struct dw_cu *cu;
};
+ALIGN_STRUCT (debug_loc_adjust)
/* Hash table and obstack for recording .debug_loc adjustment ranges. */
static htab_t loc_htab;
-static struct obstack loc_ob;
/* Hash function for loc_htab. */
static hashval_t
dso->filename);
return 1;
}
- obstack_init (&loc_ob);
}
slot = htab_find_slot_with_hash (loc_htab, &adj, adj.end_offset, INSERT);
if (slot == NULL)
goto no_memory;
if (*slot == NULL)
{
- a = obstack_alloc (&loc_ob, sizeof (*a));
+ a = pool_alloc (debug_loc_adjust, sizeof (*a));
*a = adj;
*slot = (void *) a;
}
}
last_abbrev_offset = value;
- cu = (struct dw_cu *) obstack_alloc (&ob, sizeof (struct dw_cu));
+ cu = pool_alloc (dw_cu, sizeof (struct dw_cu));
memset (cu, '\0', sizeof (*cu));
cu->cu_kind = CU_NORMAL;
cu->cu_offset = cu_offset;
|| parent->die_parent == NULL
|| parent->die_named_namespace)
{
- die = (dw_die_ref) obstack_alloc (&ob, sizeof (struct dw_die));
+ die = pool_alloc (dw_die, sizeof (struct dw_die));
memset (die, '\0', sizeof (struct dw_die));
die->die_toplevel = 1;
}
else
{
- die = (dw_die_ref)
- obstack_alloc (&ob, offsetof (struct dw_die, die_dup));
+ die = pool_alloc (dw_die, offsetof (struct dw_die, die_dup));
memset (die, '\0', offsetof (struct dw_die, die_dup));
}
*diep = die;
dw_die_ref new_die;
if (die->die_toplevel)
{
- new_die = (dw_die_ref) obstack_alloc (&ob, sizeof (struct dw_die));
+ new_die = pool_alloc (dw_die, sizeof (struct dw_die));
memset (new_die, '\0', sizeof (*new_die));
new_die->die_toplevel = 1;
die->die_dup = new_die;
}
else
{
- new_die = (dw_die_ref)
- obstack_alloc (&ob, offsetof (struct dw_die, die_dup));
+ new_die = pool_alloc (dw_die, offsetof (struct dw_die, die_dup));
memset (new_die, '\0', offsetof (struct dw_die, die_dup));
}
new_die->die_parent = parent;
static int
partition_dups (void)
{
- struct obstack vec;
unsigned int cu_off = 0;
struct dw_cu *cu, *first_partial_cu = NULL, *last_partial_cu = NULL;
size_t vec_size, i, j;
- obstack_init (&vec);
+ unsigned char *to_free = obstack_alloc (&alt_ob, 1);
for (cu = first_cu; cu; cu = cu->cu_next)
{
- partition_find_dups (&vec, cu->cu_die);
- vec_size = obstack_object_size (&vec) / sizeof (void *);
+ partition_find_dups (&alt_ob, cu->cu_die);
+ vec_size = obstack_object_size (&alt_ob) / sizeof (void *);
if (vec_size != 0)
{
- dw_die_ref *arr = (dw_die_ref *) obstack_finish (&vec);
+ dw_die_ref *arr = (dw_die_ref *) obstack_finish (&alt_ob);
qsort (arr, vec_size, sizeof (dw_die_ref), partition_cmp);
for (i = 0; i < vec_size; i = j)
{
{
dw_die_ref die, *diep;
struct dw_cu *partial_cu
- = (struct dw_cu *)
- obstack_alloc (&ob, sizeof (struct dw_cu));
+ = pool_alloc (dw_cu, sizeof (struct dw_cu));
memset (partial_cu, '\0', sizeof (*partial_cu));
partial_cu->cu_kind = CU_PU;
partial_cu->cu_offset = cu_off++;
last_partial_cu->cu_next = partial_cu;
last_partial_cu = partial_cu;
}
- die = (dw_die_ref)
- obstack_alloc (&ob, sizeof (struct dw_die));
+ die = pool_alloc (dw_die, sizeof (struct dw_die));
memset (die, '\0', sizeof (*die));
die->die_toplevel = 1;
partial_cu->cu_die = die;
ref = ref->die_parent)
{
dw_die_ref namespc
- = (dw_die_ref)
- obstack_alloc (&ob,
- sizeof (struct dw_die));
+ = pool_alloc (dw_die,
+ sizeof (struct dw_die));
memset (namespc, '\0', sizeof (struct dw_die));
namespc->die_toplevel = 1;
namespc->die_tag = ref->die_tag;
}
}
}
- obstack_free (&vec, (void *) arr);
+ obstack_free (&alt_ob, (void *) arr);
}
}
if (first_partial_cu)
last_partial_cu->cu_next = first_cu;
first_cu = first_partial_cu;
}
- obstack_free (&vec, NULL);
+ obstack_free (&alt_ob, to_free);
return 0;
}
create_import_tree (void)
{
struct dw_cu *pu, *cu, *last_partial_cu = NULL;
- struct obstack iob;
unsigned int i, new_pu_version = 2, min_cu_version, npus, ncus;
struct import_cu **ipus, *ipu, *icu;
unsigned int cu_off;
unsigned int puidx;
struct import_cu *last_pu, *pu_freelist = NULL;
+ unsigned char *to_free;
/* size doesn't count anything already created before this
function (partial units etc.) or already preexisting, just
initially the cumulative sizes of DW_TAG_imported_unit DIEs
if (first_cu == NULL || first_cu->cu_kind != CU_PU)
return 0;
- obstack_init (&iob);
+ to_free = obstack_alloc (&alt_ob, 1);
min_cu_version = first_cu->cu_version;
/* First construct a bipartite graph between CUs and PUs. */
for (pu = first_cu, npus = 0;
new_pu_version = pu->cu_version;
if (pu->cu_version < min_cu_version)
min_cu_version = pu->cu_version;
- ipu = (struct import_cu *) obstack_alloc (&iob, sizeof (*ipu));
+ ipu = (struct import_cu *) obstack_alloc (&alt_ob, sizeof (*ipu));
memset (ipu, 0, sizeof (*ipu));
ipu->cu = pu;
pu->u1.cu_icu = ipu;
prev_cu = die->die_cu;
}
ipu->incoming = (struct import_edge *)
- obstack_alloc (&iob, ipu->incoming_count
- * sizeof (*ipu->incoming));
+ obstack_alloc (&alt_ob,
+ ipu->incoming_count
+ * sizeof (*ipu->incoming));
for (die = rdie->die_nextdup, i = 0, prev_cu = NULL;
die; die = die->die_nextdup)
{
icu = die->die_cu->u1.cu_icu;
if (icu == NULL)
{
- icu = (struct import_cu *) obstack_alloc (&iob, sizeof (*ipu));
+ icu = (struct import_cu *)
+ obstack_alloc (&alt_ob, sizeof (*ipu));
memset (icu, 0, sizeof (*icu));
icu->cu = die->die_cu;
die->die_cu->u1.cu_icu = icu;
min_cu_version = cu->cu_version;
cu->u1.cu_icu->outgoing
= (struct import_edge *)
- obstack_alloc (&iob, cu->u1.cu_icu->outgoing_count
- * sizeof (*cu->u1.cu_icu->outgoing));
+ obstack_alloc (&alt_ob,
+ cu->u1.cu_icu->outgoing_count
+ * sizeof (*cu->u1.cu_icu->outgoing));
cu->u1.cu_icu->outgoing_count = 0;
}
if (ptr_size == 4 || min_cu_version > 2)
}
}
ipus = (struct import_cu **)
- obstack_alloc (&iob, (npus + ncus) * sizeof (*ipus));
+ obstack_alloc (&alt_ob, (npus + ncus) * sizeof (*ipus));
for (pu = first_cu, npus = 0;
pu && pu->cu_kind == CU_PU; pu = pu->cu_next, npus++)
{
}
else
npu = (struct import_cu *)
- obstack_alloc (&iob, sizeof (*npu));
+ obstack_alloc (&alt_ob, sizeof (*npu));
memset (npu, 0, sizeof (*npu));
npu->incoming_count = srccount;
npu->outgoing_count = dstcount;
for (ipu = ipus[npus - 1]->next; ipu; ipu = ipu->next)
{
dw_die_ref die;
- struct dw_cu *partial_cu
- = (struct dw_cu *)
- obstack_alloc (&ob, sizeof (struct dw_cu));
+ struct dw_cu *partial_cu = pool_alloc (dw_cu, sizeof (struct dw_cu));
memset (partial_cu, '\0', sizeof (*partial_cu));
partial_cu->cu_kind = CU_PU;
partial_cu->cu_offset = cu_off++;
partial_cu->cu_next = last_partial_cu->cu_next;
last_partial_cu->cu_next = partial_cu;
last_partial_cu = partial_cu;
- die = (dw_die_ref) obstack_alloc (&ob, sizeof (struct dw_die));
+ die = pool_alloc (dw_die, sizeof (struct dw_die));
memset (die, '\0', sizeof (struct dw_die));
die->die_toplevel = 1;
partial_cu->cu_die = die;
for (e = icu->outgoing; e; e = e->next)
{
dw_die_ref *diep;
- dw_die_ref die = (dw_die_ref)
- obstack_alloc (&ob, sizeof (struct dw_die));
+ dw_die_ref die = pool_alloc (dw_die, sizeof (struct dw_die));
memset (die, '\0', sizeof (*die));
die->die_toplevel = 1;
die->die_tag = DW_TAG_imported_unit;
}
for (cu = first_cu; cu; cu = cu->cu_next)
cu->u1.cu_icu = NULL;
- obstack_free (&iob, NULL);
+ obstack_free (&alt_ob, to_free);
return 0;
}
last_abbrev_offset = value;
}
- cu = (struct dw_cu *) obstack_alloc (&ob, sizeof (struct dw_cu));
+ cu = pool_alloc (dw_cu, sizeof (struct dw_cu));
memset (cu, '\0', sizeof (*cu));
cu->cu_kind = CU_TYPES;
cu->cu_new_abbrev = abbrev;
else
{
struct abbrev_tag *newt
- = (struct abbrev_tag *)
- obstack_copy (&ob, t,
- sizeof (*newt)
- + t->nattr * sizeof (struct abbrev_attr));
+ = pool_alloc (abbrev_tag,
+ sizeof (*newt) + t->nattr * sizeof (struct abbrev_attr));
+ memcpy (newt, t,
+ sizeof (*newt) + t->nattr * sizeof (struct abbrev_attr));
*slot = newt;
die->u.p2.die_new_abbrev = newt;
}
struct dw_cu *cu, **cuarr;
struct abbrev_tag *t;
unsigned int ncus, nlargeabbrevs = 0, i, laststart;
- struct obstack vec;
+ unsigned char *to_free = obstack_alloc (&alt_ob, 1);
- obstack_init (&vec);
t = (struct abbrev_tag *)
- obstack_alloc (&vec, sizeof (*t)
- + (max_nattr + 4) * sizeof (struct abbrev_attr));
+ obstack_alloc (&alt_ob,
+ sizeof (*t)
+ + (max_nattr + 4) * sizeof (struct abbrev_attr));
for (cu = first_cu, ncus = 0; cu; cu = cu->cu_next, ncus++)
{
unsigned int intracu, ndies = 0, tagsize = 0, nchildren = 0;
&cu->u2.cu_largest_entry);
continue;
}
- if (build_abbrevs (cu, t, &ndies, &vec))
- {
- obstack_free (&vec, NULL);
- return 1;
- }
+ if (build_abbrevs (cu, t, &ndies, &alt_ob))
+ return 1;
nabbrevs = htab_elements (cu->cu_new_abbrev);
htab_traverse (cu->cu_new_abbrev, list_abbrevs, &ob);
assert (obstack_object_size (&ob) == nabbrevs * sizeof (void *));
arr = (struct abbrev_tag **) obstack_finish (&ob);
- intracu = obstack_object_size (&vec) / sizeof (void *) / 2;
- obstack_ptr_grow (&vec, NULL);
- intracuarr = (dw_die_ref *) obstack_finish (&vec);
+ intracu = obstack_object_size (&alt_ob) / sizeof (void *) / 2;
+ obstack_ptr_grow (&alt_ob, NULL);
+ intracuarr = (dw_die_ref *) obstack_finish (&alt_ob);
if (nabbrevs >= 128)
{
unsigned int limit, uleb128_size;
{
error (0, 0, "%s: DW_OP_call2 or typed DWARF stack referenced DIE"
" layed out at too big offset", dso->filename);
- obstack_free (&vec, NULL);
return 1;
}
assert (*intracuvec == NULL && off == cusize);
arr[i]->hash, INSERT);
if (slot == NULL)
{
- obstack_free (&ob, (void *) arr);
- obstack_free (&vec, NULL);
error (0, ENOMEM, "Could not compute .debug_abbrev");
return 1;
}
}
}
obstack_free (&ob, (void *) arr);
- obstack_free (&vec, (void *) intracuarr);
+ obstack_free (&alt_ob, (void *) intracuarr);
cu->cu_new_offset = total_size;
total_size += cusize;
}
- obstack_free (&vec, (void *) t);
- cuarr = (struct dw_cu **) obstack_alloc (&vec,
+ obstack_free (&alt_ob, (void *) t);
+ cuarr = (struct dw_cu **) obstack_alloc (&alt_ob,
ncus * sizeof (struct dw_cu *));
for (cu = first_cu, i = 0; cu; cu = cu->cu_next)
if (cu->u1.cu_new_abbrev_owner == NULL)
if (cuarr[i]->u1.cu_new_abbrev_owner != NULL)
continue;
nabbrevs = htab_elements (cuarr[i]->cu_new_abbrev);
- htab_traverse (cuarr[i]->cu_new_abbrev, list_abbrevs, &vec);
- assert (obstack_object_size (&vec) == nabbrevs * sizeof (void *));
- arr = (struct abbrev_tag **) obstack_finish (&vec);
+ htab_traverse (cuarr[i]->cu_new_abbrev, list_abbrevs, &alt_ob);
+ assert (obstack_object_size (&alt_ob) == nabbrevs * sizeof (void *));
+ arr = (struct abbrev_tag **) obstack_finish (&alt_ob);
if (nabbrevs >= 128)
{
nattempts = 0;
INSERT);
if (slot == NULL)
{
- obstack_free (&vec, NULL);
error (0, ENOMEM, "Could not compute .debug_abbrev");
return 1;
}
{
struct abbrev_tag *newt;
arr[k]->entry = ++entry;
- newt = (struct abbrev_tag *)
- obstack_copy (&ob, arr[k],
- sizeof (*newt)
- + arr[k]->nattr
- * sizeof (struct abbrev_attr));
+ newt = pool_alloc (abbrev_tag,
+ sizeof (*newt)
+ + arr[k]->nattr
+ * sizeof (struct abbrev_attr));
+ memcpy (newt, arr[k],
+ sizeof (*newt)
+ + arr[k]->nattr * sizeof (struct abbrev_attr));
*slot = newt;
}
}
cuarr[i]->u1.cu_new_abbrev_owner = cuarr[j];
break;
}
- obstack_free (&vec, (void *) arr);
+ obstack_free (&alt_ob, (void *) arr);
continue;
}
/* Don't search all CUs, that might be too expensive. So just search
INSERT);
if (slot == NULL)
{
- obstack_free (&vec, NULL);
error (0, ENOMEM, "Could not compute .debug_abbrev");
return 1;
}
{
struct abbrev_tag *newt;
arr[k]->entry = ++entry;
- newt = (struct abbrev_tag *)
- obstack_copy (&ob, arr[k],
- sizeof (*newt)
- + arr[k]->nattr
- * sizeof (struct abbrev_attr));
+ newt = pool_alloc (abbrev_tag,
+ sizeof (*newt)
+ + arr[k]->nattr
+ * sizeof (struct abbrev_attr));
+ memcpy (newt, arr[k],
+ sizeof (*newt)
+ + arr[k]->nattr * sizeof (struct abbrev_attr));
*slot = newt;
}
}
cuarr[i]->u1.cu_new_abbrev_owner = cuarr[j];
}
}
- obstack_free (&vec, (void *) arr);
+ obstack_free (&alt_ob, (void *) arr);
}
- obstack_free (&vec, NULL);
+ obstack_free (&alt_ob, to_free);
for (cu = first_cu; cu; cu = cu->cu_next)
{
struct abbrev_tag **arr;
exit (1);
obstack_init (&ob);
+ obstack_init (&alt_ob);
if (read_dwarf (dso))
exit (1);
off_htab = NULL;
if (loc_htab != NULL)
{
- obstack_free (&loc_ob, NULL);
htab_delete (loc_htab);
loc_htab = NULL;
}
+ obstack_free (&alt_ob, NULL);
obstack_free (&ob, NULL);
+ pool_destroy ();
write_dso (dso, outfile, new_debug_abbrev, new_debug_abbrev_size,
new_debug_info, new_debug_info_size, new_debug_loc,