Index: gcc/gcc/vec.c |
diff --git a/gcc/gcc/vec.c b/gcc/gcc/vec.c |
index 14567827dcd1a20c3cc4b73bc2383cb739c74350..078bcc636539891e25d35a9cbcfc01ca9d318217 100644 |
--- a/gcc/gcc/vec.c |
+++ b/gcc/gcc/vec.c |
@@ -33,7 +33,7 @@ along with GCC; see the file COPYING3. If not see |
#include "toplev.h" |
#include "hashtab.h" |
-struct vec_prefix |
+struct vec_prefix |
{ |
unsigned num; |
unsigned alloc; |
@@ -113,7 +113,8 @@ vec_descriptor (const char *name, int line, const char *function) |
if (!vec_desc_hash) |
vec_desc_hash = htab_create (10, hash_descriptor, eq_descriptor, NULL); |
- slot = (struct vec_descriptor **) htab_find_slot (vec_desc_hash, &loc, 1); |
+ slot = (struct vec_descriptor **) htab_find_slot (vec_desc_hash, &loc, |
+ INSERT); |
if (*slot) |
return *slot; |
*slot = XCNEW (struct vec_descriptor); |
@@ -189,10 +190,10 @@ calculate_allocation (const struct vec_prefix *pfx, int reserve, bool exact) |
/* If there's no prefix, and we've not requested anything, then we |
will create a NULL vector. */ |
return 0; |
- |
+ |
/* We must have run out of room. */ |
gcc_assert (alloc - num < (unsigned) reserve); |
- |
+ |
if (exact) |
/* Exact size. */ |
alloc = num + reserve; |
@@ -207,7 +208,7 @@ calculate_allocation (const struct vec_prefix *pfx, int reserve, bool exact) |
else |
/* Grow slower when large. */ |
alloc = (alloc * 3 / 2); |
- |
+ |
/* If this is still too small, set it to the right size. */ |
if (alloc < num + reserve) |
alloc = num + reserve; |
@@ -226,20 +227,20 @@ vec_gc_o_reserve_1 (void *vec, int reserve, size_t vec_offset, size_t elt_size, |
bool exact MEM_STAT_DECL) |
{ |
struct vec_prefix *pfx = (struct vec_prefix *) vec; |
- unsigned alloc = alloc = calculate_allocation (pfx, reserve, exact); |
- |
+ unsigned alloc = calculate_allocation (pfx, reserve, exact); |
+ |
if (!alloc) |
{ |
if (pfx) |
ggc_free (pfx); |
return NULL; |
} |
- |
+ |
vec = ggc_realloc_stat (vec, vec_offset + alloc * elt_size PASS_MEM_STAT); |
((struct vec_prefix *)vec)->alloc = alloc; |
if (!pfx) |
((struct vec_prefix *)vec)->num = 0; |
- |
+ |
return vec; |
} |
@@ -315,7 +316,7 @@ vec_heap_o_reserve_1 (void *vec, int reserve, size_t vec_offset, |
if (vec) |
free_overhead (pfx); |
#endif |
- |
+ |
vec = xrealloc (vec, vec_offset + alloc * elt_size); |
((struct vec_prefix *)vec)->alloc = alloc; |
if (!pfx) |
@@ -325,7 +326,7 @@ vec_heap_o_reserve_1 (void *vec, int reserve, size_t vec_offset, |
register_overhead ((struct vec_prefix *)vec, |
vec_offset + alloc * elt_size PASS_MEM_STAT); |
#endif |
- |
+ |
return vec; |
} |
@@ -371,6 +372,147 @@ vec_heap_o_reserve_exact (void *vec, int reserve, size_t vec_offset, |
PASS_MEM_STAT); |
} |
+/* Stack vectors are a little different. VEC_alloc turns into a call |
+ to vec_stack_p_reserve_exact1 and passes in space allocated via a |
+ call to alloca. We record that pointer so that we know that we |
+ shouldn't free it. If the vector is resized, we resize it on the |
+ heap. We record the pointers in a vector and search it in LIFO |
+ order--i.e., we look for the newest stack vectors first. We don't |
+ expect too many stack vectors at any one level, and searching from |
+ the end should normally be efficient even if they are used in a |
+ recursive function. */ |
+ |
+typedef void *void_p; |
+DEF_VEC_P(void_p); |
+DEF_VEC_ALLOC_P(void_p,heap); |
+ |
+static VEC(void_p,heap) *stack_vecs; |
+ |
+/* Allocate a vector which uses alloca for the initial allocation. |
+ SPACE is space allocated using alloca, ALLOC is the number of |
+ entries allocated. */ |
+ |
+void * |
+vec_stack_p_reserve_exact_1 (int alloc, void *space) |
+{ |
+ struct vec_prefix *pfx = (struct vec_prefix *) space; |
+ |
+ VEC_safe_push (void_p, heap, stack_vecs, space); |
+ |
+ pfx->num = 0; |
+ pfx->alloc = alloc; |
+ |
+ return space; |
+} |
+ |
+/* Grow a vector allocated using alloca. When this happens, we switch |
+ back to heap allocation. We remove the vector from stack_vecs, if |
+ it is there, since we no longer need to avoid freeing it. */ |
+ |
+static void * |
+vec_stack_o_reserve_1 (void *vec, int reserve, size_t vec_offset, |
+ size_t elt_size, bool exact MEM_STAT_DECL) |
+{ |
+ bool found; |
+ unsigned int ix; |
+ void *newvec; |
+ |
+ found = false; |
+ for (ix = VEC_length (void_p, stack_vecs); ix > 0; --ix) |
+ { |
+ if (VEC_index (void_p, stack_vecs, ix - 1) == vec) |
+ { |
+ VEC_unordered_remove (void_p, stack_vecs, ix - 1); |
+ found = true; |
+ break; |
+ } |
+ } |
+ |
+ if (!found) |
+ { |
+ /* VEC is already on the heap. */ |
+ return vec_heap_o_reserve_1 (vec, reserve, vec_offset, elt_size, |
+ exact PASS_MEM_STAT); |
+ } |
+ |
+ /* Move VEC to the heap. */ |
+ reserve += ((struct vec_prefix *) vec)->num; |
+ newvec = vec_heap_o_reserve_1 (NULL, reserve, vec_offset, elt_size, |
+ exact PASS_MEM_STAT); |
+ if (newvec && vec) |
+ { |
+ ((struct vec_prefix *) newvec)->num = ((struct vec_prefix *) vec)->num; |
+ memcpy (((struct vec_prefix *) newvec)->vec, |
+ ((struct vec_prefix *) vec)->vec, |
+ ((struct vec_prefix *) vec)->num * elt_size); |
+ } |
+ return newvec; |
+} |
+ |
+/* Grow a vector allocated on the stack. */ |
+ |
+void * |
+vec_stack_p_reserve (void *vec, int reserve MEM_STAT_DECL) |
+{ |
+ return vec_stack_o_reserve_1 (vec, reserve, |
+ offsetof (struct vec_prefix, vec), |
+ sizeof (void *), false |
+ PASS_MEM_STAT); |
+} |
+ |
+/* Exact version of vec_stack_p_reserve. */ |
+ |
+void * |
+vec_stack_p_reserve_exact (void *vec, int reserve MEM_STAT_DECL) |
+{ |
+ return vec_stack_o_reserve_1 (vec, reserve, |
+ offsetof (struct vec_prefix, vec), |
+ sizeof (void *), true |
+ PASS_MEM_STAT); |
+} |
+ |
+/* Like vec_stack_p_reserve, but for objects. */ |
+ |
+void * |
+vec_stack_o_reserve (void *vec, int reserve, size_t vec_offset, |
+ size_t elt_size MEM_STAT_DECL) |
+{ |
+ return vec_stack_o_reserve_1 (vec, reserve, vec_offset, elt_size, false |
+ PASS_MEM_STAT); |
+} |
+ |
+/* Like vec_stack_p_reserve_exact, but for objects. */ |
+ |
+void * |
+vec_stack_o_reserve_exact (void *vec, int reserve, size_t vec_offset, |
+ size_t elt_size MEM_STAT_DECL) |
+{ |
+ return vec_stack_o_reserve_1 (vec, reserve, vec_offset, elt_size, true |
+ PASS_MEM_STAT); |
+} |
+ |
+/* Free a vector allocated on the stack. Don't actually free it if we |
+ find it in the hash table. */ |
+ |
+void |
+vec_stack_free (void *vec) |
+{ |
+ unsigned int ix; |
+ |
+ for (ix = VEC_length (void_p, stack_vecs); ix > 0; --ix) |
+ { |
+ if (VEC_index (void_p, stack_vecs, ix - 1) == vec) |
+ { |
+ VEC_unordered_remove (void_p, stack_vecs, ix - 1); |
+ return; |
+ } |
+ } |
+ |
+ /* VEC was not on the list of vecs allocated on the stack, so it |
+ must be allocated on the heap. */ |
+ vec_heap_free (vec); |
+} |
+ |
#if ENABLE_CHECKING |
/* Issue a vector domain error, and then fall over. */ |