Commit 005537df by Richard Henderson

Simplified GC interface and other goodies.

From-SVN: r29946
parent 1f1479dc
......@@ -1750,7 +1750,7 @@ s-output : $(md_file) genoutput $(srcdir)/move-if-change
$(SHELL) $(srcdir)/move-if-change tmp-output.c insn-output.c
touch s-output
genrtl.o : genrtl.c $(CONFIG_H) $(RTL_H) system.h
genrtl.o : genrtl.c $(CONFIG_H) $(RTL_H) system.h ggc.h
genrtl.c genrtl.h : s-genrtl
@true # force gnu make to recheck modification times.
......
......@@ -324,6 +324,9 @@
/* Define if you have the sysconf function. */
#undef HAVE_SYSCONF
/* Define if you have the valloc function. */
#undef HAVE_VALLOC
/* Define if you have the <argz.h> header file. */
#undef HAVE_ARGZ_H
......
......@@ -368,7 +368,7 @@ fi
AC_CHECK_FUNCS(strtoul bsearch strerror putenv popen bcopy bzero bcmp \
index rindex strchr strrchr kill getrlimit setrlimit atoll atoq \
sysconf isascii gettimeofday strsignal putc_unlocked fputc_unlocked \
fputs_unlocked getrusage)
fputs_unlocked getrusage valloc)
# Make sure wchar_t is available
#AC_CHECK_TYPE(wchar_t, unsigned int)
......@@ -4456,6 +4456,8 @@ AC_ARG_WITH(gc,
esac],
[if test $ac_cv_func_mmap_fixed_mapped = yes; then
GGC=ggc-page
elif test $ac_cv_func_valloc = yes; then
GGC=ggc-page
else
GGC=ggc-simple
fi])
......
......@@ -268,21 +268,18 @@ ggc_mark_rtx_children (r)
ggc_mark_rtvec (XVEC (r, i));
break;
case 'S': case 's':
ggc_mark_string_if_gcable (XSTR (r, i));
ggc_mark_if_gcable (XSTR (r, i));
break;
}
}
}
void
ggc_mark_rtvec (v)
ggc_mark_rtvec_children (v)
rtvec v;
{
int i;
if (v == NULL || ggc_set_mark_rtvec (v))
return;
i = GET_NUM_ELEM (v);
while (--i >= 0)
ggc_mark_rtx (RTVEC_ELT (v, i));
......@@ -451,3 +448,26 @@ ggc_mark_tree_hash_table (ht)
hash_traverse (ht, ggc_mark_tree_hash_table_entry, /*info=*/0);
}
/* Allocation wrappers. */
char *
ggc_alloc_string (contents, length)
const char *contents;
int length;
{
char *string;
if (length < 0)
{
if (contents == NULL)
return NULL;
length = strlen (contents);
}
string = (char *) ggc_alloc_obj (length + 1, 0);
if (contents != NULL)
memcpy (string, contents, length);
string[length] = 0;
return string;
}
......@@ -35,28 +35,13 @@
/* For now, keep using the old obstack scheme in the gen* programs. */
int ggc_p = 0;
rtx
ggc_alloc_rtx (nslots)
int nslots;
void *
ggc_alloc_obj (size, zero)
size_t size;
int zero;
{
int size = sizeof(struct rtx_def) + (nslots - 1) * sizeof(rtunion);
rtx n;
n = (rtx) xmalloc (size);
bzero ((char *) n, size);
return n;
}
rtvec
ggc_alloc_rtvec (nelt)
int nelt;
{
int size = sizeof (struct rtvec_def) + (nelt - 1) * sizeof (rtx);
rtvec v;
v = (rtvec) xmalloc (size);
bzero ((char *) v, size);
return v;
void *p = xmalloc (size);
if (zero)
memset (p, 0, size);
return p;
}
......@@ -27,7 +27,9 @@
#include "flags.h"
#include "ggc.h"
#ifdef HAVE_MMAP
#include <sys/mman.h>
#endif
/* Stategy:
......@@ -111,10 +113,10 @@ char *empty_string;
significant PAGE_L2_BITS and PAGE_L1_BITS are the second and first
index values in the lookup table, respectively.
The topmost leftover bits, if any, are ignored. For 32-bit
architectures and the settings below, there are no leftover bits.
For architectures with wider pointers, the lookup tree points to a
list of pages, which must be scanned to find the correct one. */
For 32-bit architectures and the settings below, there are no
leftover bits. For architectures with wider pointers, the lookup
tree points to a list of pages, which must be scanned to find the
correct one. */
#define PAGE_L1_BITS (8)
#define PAGE_L2_BITS (32 - PAGE_L1_BITS - G.lg_pagesize)
......@@ -178,8 +180,8 @@ typedef page_entry **page_table[PAGE_L1_SIZE];
#else
/* On 64-bit hosts, we use two level page tables plus a linked list
that disambiguates the top 32-bits. There will almost always be
/* On 64-bit hosts, we use the same two level page tables plus a linked
list that disambiguates the top 32-bits. There will almost always be
exactly one entry in the list. */
typedef struct page_table_chain
{
......@@ -221,7 +223,7 @@ static struct globals
unsigned char context_depth;
/* A file descriptor open to /dev/zero for reading. */
#ifndef MAP_ANONYMOUS
#if defined (HAVE_MMAP) && !defined(MAP_ANONYMOUS)
int dev_zero_fd;
#endif
......@@ -258,16 +260,13 @@ static struct globals
#define GGC_MIN_LAST_ALLOCATED (4 * 1024 * 1024)
static page_entry *** ggc_lookup_page_table PROTO ((void));
static int ggc_allocated_p PROTO ((const void *));
static page_entry *lookup_page_table_entry PROTO ((void *));
static page_entry *lookup_page_table_entry PROTO ((const void *));
static void set_page_table_entry PROTO ((void *, page_entry *));
static char *alloc_anon PROTO ((char *, size_t));
static struct page_entry * alloc_page PROTO ((unsigned));
static void free_page PROTO ((struct page_entry *));
static void release_pages PROTO ((void));
static void *alloc_obj PROTO ((size_t, int));
static int mark_obj PROTO ((void *));
static void clear_marks PROTO ((void));
static void sweep_pages PROTO ((void));
......@@ -278,37 +277,31 @@ static void poison_pages PROTO ((void));
void debug_print_page_list PROTO ((int));
/* Returns the lookup table appropriate for looking up P. */
/* Returns non-zero if P was allocated in GC'able memory. */
static inline page_entry ***
ggc_lookup_page_table ()
static inline int
ggc_allocated_p (p)
const void *p;
{
page_entry ***base;
size_t L1, L2;
#if HOST_BITS_PER_PTR <= 32
base = &G.lookup[0];
#else
page_table table = G.lookup;
size_t high_bits = (size_t) p & ~ (size_t) 0xffffffff;
while (table->high_bits != high_bits)
table = table->next;
while (1)
{
if (table == NULL)
return 0;
if (table->high_bits == high_bits)
break;
table = table->next;
}
base = &table->table[0];
#endif
return base;
}
/* Returns non-zero if P was allocated in GC'able memory. */
static inline int
ggc_allocated_p (p)
const void *p;
{
page_entry ***base;
size_t L1, L2;
base = ggc_lookup_page_table ();
/* Extract the level 1 and 2 indicies. */
L1 = LOOKUP_L1 (p);
L2 = LOOKUP_L2 (p);
......@@ -321,12 +314,20 @@ ggc_allocated_p (p)
static inline page_entry *
lookup_page_table_entry(p)
void *p;
const void *p;
{
page_entry ***base;
size_t L1, L2;
base = ggc_lookup_page_table ();
#if HOST_BITS_PER_PTR <= 32
base = &G.lookup[0];
#else
page_table table = G.lookup;
size_t high_bits = (size_t) p & ~ (size_t) 0xffffffff;
while (table->high_bits != high_bits)
table = table->next;
base = &table->table[0];
#endif
/* Extract the level 1 and 2 indicies. */
L1 = LOOKUP_L1 (p);
......@@ -407,11 +408,12 @@ poison (start, len)
(if non-null). */
static inline char *
alloc_anon (pref, size)
char *pref;
char *pref ATTRIBUTE_UNUSED;
size_t size;
{
char *page;
#ifdef HAVE_MMAP
#ifdef MAP_ANONYMOUS
page = (char *) mmap (pref, size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
......@@ -424,6 +426,16 @@ alloc_anon (pref, size)
fputs ("Virtual memory exhausted!\n", stderr);
exit(1);
}
#else
#ifdef HAVE_VALLOC
page = (char *) valloc (size);
if (!page)
{
fputs ("Virtual memory exhausted!\n", stderr);
exit(1);
}
#endif /* HAVE_VALLOC */
#endif /* HAVE_MMAP */
return page;
}
......@@ -522,6 +534,7 @@ free_page (entry)
static inline void
release_pages ()
{
#ifdef HAVE_MMAP
page_entry *p, *next;
char *start;
size_t len;
......@@ -553,6 +566,19 @@ release_pages ()
}
munmap (start, len);
#else
#ifdef HAVE_VALLOC
page_entry *p, *next;
for (p = G.free_pages; p ; p = next)
{
next = p->next;
free (p->page);
free (p);
}
#endif /* HAVE_VALLOC */
#endif /* HAVE_MMAP */
G.free_pages = NULL;
}
......@@ -582,8 +608,8 @@ static unsigned char const size_lookup[257] =
/* Allocate a chunk of memory of SIZE bytes. If ZERO is non-zero, the
memory is zeroed; otherwise, its contents are undefined. */
static void *
alloc_obj (size, zero)
void *
ggc_alloc_obj (size, zero)
size_t size;
int zero;
{
......@@ -700,8 +726,8 @@ alloc_obj (size, zero)
/* If P is not marked, marks it and returns 0. Otherwise returns 1.
P must have been allocated by the GC allocator; it mustn't point to
static objects, stack variables, or memory allocated with malloc. */
static int
mark_obj (p)
int
ggc_set_mark (p)
void *p;
{
page_entry *entry;
......@@ -738,6 +764,13 @@ mark_obj (p)
return 0;
}
void
ggc_mark_if_gcable (p)
void *p;
{
if (p && ggc_allocated_p (p))
ggc_set_mark (p);
}
/* Initialize the ggc-mmap allocator. */
void
......@@ -746,7 +779,7 @@ init_ggc ()
G.pagesize = getpagesize();
G.lg_pagesize = exact_log2 (G.pagesize);
#ifndef MAP_ANONYMOUS
#if defined (HAVE_MMAP) && !defined(MAP_ANONYMOUS)
G.dev_zero_fd = open ("/dev/zero", O_RDONLY);
if (G.dev_zero_fd == -1)
abort ();
......@@ -812,64 +845,6 @@ ggc_pop_context ()
}
}
}
struct rtx_def *
ggc_alloc_rtx (nslots)
int nslots;
{
return (struct rtx_def *)
alloc_obj (sizeof (struct rtx_def) + (nslots - 1) * sizeof (rtunion), 1);
}
struct rtvec_def *
ggc_alloc_rtvec (nelt)
int nelt;
{
return (struct rtvec_def *)
alloc_obj (sizeof (struct rtvec_def) + (nelt - 1) * sizeof (rtx), 1);
}
union tree_node *
ggc_alloc_tree (length)
int length;
{
return (union tree_node *) alloc_obj (length, 1);
}
char *
ggc_alloc_string (contents, length)
const char *contents;
int length;
{
char *string;
if (length < 0)
{
if (contents == NULL)
return NULL;
length = strlen (contents);
}
string = (char *) alloc_obj (length + 1, 0);
if (contents != NULL)
memcpy (string, contents, length);
string[length] = 0;
return string;
}
void *
ggc_alloc (size)
size_t size;
{
return alloc_obj (size, 0);
}
static inline void
clear_marks ()
......@@ -1072,54 +1047,9 @@ ggc_collect ()
time = get_run_time () - time;
gc_time += time;
time = (time + 500) / 1000;
if (!quiet_flag)
fprintf (stderr, "%luk in %d.%03d}",
(unsigned long) G.allocated / 1024, time / 1000, time % 1000);
}
int
ggc_set_mark_rtx (r)
rtx r;
{
return mark_obj (r);
}
int
ggc_set_mark_rtvec (v)
rtvec v;
{
return mark_obj (v);
}
int
ggc_set_mark_tree (t)
tree t;
{
return mark_obj (t);
}
void
ggc_mark_string (s)
char *s;
{
if (s)
mark_obj (s);
}
void
ggc_mark_string_if_gcable (s)
char *s;
{
if (s && ggc_allocated_p (s))
mark_obj (s);
}
void
ggc_mark (p)
void *p;
{
if (p)
mark_obj (p);
{
fprintf (stderr, "%luk in %.3f}",
(unsigned long) G.allocated / 1024, time * 1e-6);
}
}
......@@ -56,34 +56,52 @@ void ggc_del_root PROTO ((void *base));
/* Mark nodes from the gc_add_root callback. These functions follow
pointers to mark other objects too. */
extern void ggc_mark_rtvec PROTO ((struct rtvec_def *));
extern void ggc_mark_tree_varray PROTO ((struct varray_head_tag *));
extern void ggc_mark_tree_hash_table PROTO ((struct hash_table *));
extern void ggc_mark_string PROTO ((char *));
extern void ggc_mark PROTO ((void *));
extern void ggc_mark_roots PROTO((void));
extern void ggc_mark_rtx_children PROTO ((struct rtx_def *));
extern void ggc_mark_rtvec_children PROTO ((struct rtvec_def *));
extern void ggc_mark_tree_children PROTO ((union tree_node *));
/* Mark the string, but only if it was allocated in collectable
memory. */
extern void ggc_mark_string_if_gcable PROTO ((char *));
#define ggc_mark_rtx(EXPR) \
do { \
rtx r__ = (EXPR); \
if (r__ != NULL && ! ggc_set_mark (r__)) \
ggc_mark_rtx_children (r__); \
} while (0)
#define ggc_mark_tree(EXPR) \
do { \
tree t__ = (EXPR); \
if (t__ != NULL && ! ggc_set_mark (t__)) \
ggc_mark_tree_children (t__); \
} while (0)
#define ggc_mark_rtx(RTX_EXPR) \
do { \
rtx r__ = (RTX_EXPR); \
if (r__ != NULL && ! ggc_set_mark_rtx (r__)) \
ggc_mark_rtx_children (r__); \
#define ggc_mark_rtvec(EXPR) \
do { \
rtvec v__ = (EXPR); \
if (v__ != NULL && ! ggc_set_mark (v__)) \
ggc_mark_rtvec_children (v__); \
} while (0)
#define ggc_mark_tree(TREE_EXPR) \
do { \
tree t__ = (TREE_EXPR); \
if (t__ != NULL && ! ggc_set_mark_tree (t__)) \
ggc_mark_tree_children (t__); \
#define ggc_mark_string(EXPR) \
do { \
char *s__ = (EXPR); \
if (s__ != NULL) \
ggc_set_mark (s__); \
} while (0)
#define ggc_mark(EXPR) \
do { \
void *a__ = (EXPR); \
if (a__ != NULL) \
ggc_set_mark (a__); \
} while (0)
/* Mark, but only if it was allocated in collectable memory. */
extern void ggc_mark_if_gcable PROTO ((void *));
/* A GC implementation must provide these functions. */
/* Initialize the garbage collector. */
......@@ -98,24 +116,35 @@ extern void ggc_push_context PROTO ((void));
extern void ggc_pop_context PROTO ((void));
/* Allocation. */
struct rtx_def *ggc_alloc_rtx PROTO ((int nslots));
struct rtvec_def *ggc_alloc_rtvec PROTO ((int nelt));
union tree_node *ggc_alloc_tree PROTO ((int length));
/* The internal primitive. */
void *ggc_alloc_obj PROTO ((size_t, int));
#define ggc_alloc_rtx(NSLOTS) \
((struct rtx_def *) ggc_alloc_obj (sizeof (struct rtx_def) \
+ ((NSLOTS) - 1) * sizeof (rtunion), 1))
#define ggc_alloc_rtvec(NELT) \
((struct rtvec_def *) ggc_alloc_obj (sizeof (struct rtvec_def) \
+ ((NELT) - 1) * sizeof (rtx), 1))
#define ggc_alloc_tree(LENGTH) \
((union tree_node *) ggc_alloc_obj ((LENGTH), 1))
#define ggc_alloc(SIZE) ggc_alloc_obj((SIZE), 0)
char *ggc_alloc_string PROTO ((const char *contents, int length));
void *ggc_alloc PROTO ((size_t));
/* Invoke the collector. This is really just a hint, but in the case of
the simple collector, the only time it will happen. */
void ggc_collect PROTO ((void));
/* Actually set the mark on a particular region of memory, but don't
follow pointers. These functions are called by ggc_mark_*. They
return zero if the object was not previously marked; they return
non-zero if the object was already marked, or if, for any other
reason, pointers in this data structure should not be traversed. */
int ggc_set_mark_rtx PROTO ((struct rtx_def *));
int ggc_set_mark_rtvec PROTO ((struct rtvec_def *));
int ggc_set_mark_tree PROTO ((union tree_node *));
follow pointers. This function is called by ggc_mark_*. It
returns zero if the object was not previously marked; non-zero if
the object was already marked, or if, for any other reason,
pointers in this data structure should not be traversed. */
int ggc_set_mark PROTO ((void *));
/* Callbacks to the languages. */
......
......@@ -102,18 +102,15 @@ typedef struct rtx_def
{
#ifdef ONLY_INT_FIELDS
#ifdef CODE_FIELD_BUG
unsigned int code : 15;
unsigned int code : 16;
#else
unsigned short code;
#endif
#else
/* The kind of expression this is. */
enum rtx_code code : 15;
enum rtx_code code : 16;
#endif
/* Used by the garbage collector. */
unsigned gc_mark : 1;
/* The kind of value the expression has. */
#ifdef ONLY_INT_FIELDS
int mode : 8;
......@@ -207,7 +204,6 @@ typedef struct rtx_def
typedef struct rtvec_def{
int num_elem; /* number of elements */
int gc_mark;
struct rtx_def *elem[1];
} *rtvec;
......
......@@ -203,9 +203,7 @@ struct tree_common
unsigned lang_flag_5 : 1;
unsigned lang_flag_6 : 1;
unsigned gc_mark : 1;
/* There is room for two more flags. */
/* There is room for three more flags. */
};
/* The following table lists the uses of each of the above flags and
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment