Makefile.in (OBJS, [...]): Update.

* Makefile.in (OBJS, LIBCPP_OBJS, LIBCPP_DEPS,
	cpplib.o, cpphash.o, fix-header): Update.
	(hashtable.o): New target.
	* c-common.h: Include cpplib.h.  Define C_RID_CODE and
	struct c_common_identifier here.
	* c-lang.c (c_init_options): Update.  Call set_identifier_size.
	* c-lex.c (c_lex): Update.
	* c-pragma.h: Update.
	* c-tree.h (struct lang_identifier): Contain c_common_identifier.
	Delete rid_code.
	(C_RID_CODE): Delete.
	* cpphash.c: Rewrite to use hashtable.c.
	* cpphash.h: Update include guards.
	(struct cpp_reader): Remove hashtab.
	hash_ob and buffer_ob are no longer pointers.  Add hash_table
	and our_hashtable.
	(HASHSTEP, _cpp_init_hashtable,	_cpp_lookup_with_hash): Delete.
	(_cpp_cleanup_hashtable): Rename _cpp_destroy_hashtable.
	(_cpp_cleanup_stacks): Rename _cpp_init_directives.
	* cppinit.c (cpp_create_reader): Update.
	* cpplex.c (cpp_ideq, parse_identifier, cpp_output_token): Update.
	(cpp_interpret_charconst): Eliminate warning.
	* cpplib.c (do_pragma, do_endif, push_conditional,
	cpp_push_buffer, cpp_pop_buffer): Update.
	(_cpp_init_stacks): Rename cpp_init_directives.
	(_cpp_cleanup_stacks): Remove.
	* cpplib.h: Update include guards.  Include tree-core.h and c-rid.h.
	(cpp_hashnode, cpp_token, NODE_LEN, NODE_NAME,
	 cpp_forall_identifiers, cpp_create_reader): Update.
	(C_RID_CODE, cpp_make_node): New.
	(c_common_identifier): New identifier node for C front ends.
	* cppmain.c (main): Update.
	* fix-header.c (read_scan_file): Update.
	* flags.h (id_clash_len): Make unsigned.
	* ggc.h (ggc_mark_nonnull_tree): New.
	* hashtable.c: New.
	* hashtable.h: New.
	* stringpool.c: Update comments and copyright.  Update to use
	hashtable.c.
	* toplev.c (approx_sqrt): Move to hashtable.c.
	(id_clash_len): Make unsigned.
	* toplev.h (ident_hash): New.
	* tree.c (gcc_obstack_init): Move to hashtable.c.
	* tree.h: Include hashtable.h.
	(IDENTIFIER_POINTER, IDENTIFIER_LENGTH): Update.
	(GCC_IDENT_TO_HT_IDENT, HT_IDENT_TO_GCC_IDENT): New.
	(struct tree_identifier): Update.
	(make_identifier): New.
cp:
	* cp-tree.h (struct lang_identifier, C_RID_YYCODE): Update.
	(C_RID_CODE): Remove.
	* lex.c (cxx_init_options): Call set_identifier_size.  Update.
	(init_parse): Don't do it here.
objc:
	* objc-act.c (objc_init_options): Call set_identifier_size. Update.

From-SVN: r42334
This commit is contained in:
Neil Booth 2001-05-20 06:26:45 +00:00 committed by Neil Booth
parent 9e800206ba
commit 2a967f3d3a
29 changed files with 804 additions and 674 deletions

View File

@ -1,3 +1,61 @@
2001-05-20 Neil Booth <neil@daikokuya.demon.co.uk>
* Makefile.in (OBJS, LIBCPP_OBJS, LIBCPP_DEPS,
cpplib.o, cpphash.o, fix-header): Update.
(hashtable.o): New target.
* c-common.h: Include cpplib.h. Define C_RID_CODE and
struct c_common_identifier here.
* c-lang.c (c_init_options): Update. Call set_identifier_size.
* c-lex.c (c_lex): Update.
* c-pragma.h: Update.
* c-tree.h (struct lang_identifier): Contain c_common_identifier.
Delete rid_code.
(C_RID_CODE): Delete.
* cpphash.c: Rewrite to use hashtable.c.
* cpphash.h: Update include guards.
(struct cpp_reader): Remove hashtab.
hash_ob and buffer_ob are no longer pointers. Add hash_table
and our_hashtable.
(HASHSTEP, _cpp_init_hashtable, _cpp_lookup_with_hash): Delete.
(_cpp_cleanup_hashtable): Rename _cpp_destroy_hashtable.
(_cpp_cleanup_stacks): Rename _cpp_init_directives.
* cppinit.c (cpp_create_reader): Update.
* cpplex.c (cpp_ideq, parse_identifier, cpp_output_token): Update.
(cpp_interpret_charconst): Eliminate warning.
* cpplib.c (do_pragma, do_endif, push_conditional,
cpp_push_buffer, cpp_pop_buffer): Update.
(_cpp_init_stacks): Rename cpp_init_directives.
(_cpp_cleanup_stacks): Remove.
* cpplib.h: Update include guards. Include tree-core.h and c-rid.h.
(cpp_hashnode, cpp_token, NODE_LEN, NODE_NAME,
cpp_forall_identifiers, cpp_create_reader): Update.
(C_RID_CODE, cpp_make_node): New.
(c_common_identifier): New identifier node for C front ends.
* cppmain.c (main): Update.
* fix-header.c (read_scan_file): Update.
* flags.h (id_clash_len): Make unsigned.
* ggc.h (ggc_mark_nonnull_tree): New.
* hashtable.c: New.
* hashtable.h: New.
* stringpool.c: Update comments and copyright. Update to use
hashtable.c.
* toplev.c (approx_sqrt): Move to hashtable.c.
(id_clash_len): Make unsigned.
* toplev.h (ident_hash): New.
* tree.c (gcc_obstack_init): Move to hashtable.c.
* tree.h: Include hashtable.h.
(IDENTIFIER_POINTER, IDENTIFIER_LENGTH): Update.
(GCC_IDENT_TO_HT_IDENT, HT_IDENT_TO_GCC_IDENT): New.
(struct tree_identifier): Update.
(make_identifier): New.
cp:
* cp-tree.h (struct lang_identifier, C_RID_YYCODE): Update.
(C_RID_CODE): Remove.
* lex.c (cxx_init_options): Call set_identifier_size. Update.
(init_parse): Don't do it here.
objc:
* objc-act.c (objc_init_options): Call set_identifier_size. Update.
Sat May 19 18:23:04 2001 Richard Henderson <rth@redhat.com>
* except.c (dw2_build_landing_pads): Use word_mode, not Pmode,

View File

@ -706,7 +706,7 @@ OBJS = \
dependence.o diagnostic.o doloop.o dominance.o dwarf2asm.o dwarf2out.o \
dwarfout.o emit-rtl.o except.o explow.o expmed.o expr.o final.o flow.o \
fold-const.o function.o gcse.o genrtl.o ggc-common.o global.o graph.o \
haifa-sched.o hash.o ifcvt.o insn-attrtab.o insn-emit.o \
haifa-sched.o hash.o hashtable.o ifcvt.o insn-attrtab.o insn-emit.o \
insn-extract.o insn-opinit.o insn-output.o insn-peep.o insn-recog.o \
integrate.o intl.o jump.o lcm.o lists.o local-alloc.o loop.o mbchar.o \
optabs.o params.o predict.o print-rtl.o print-tree.o profile.o real.o \
@ -1294,6 +1294,8 @@ ggc-page.o: ggc-page.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \
stringpool.o: stringpool.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(OBSTACK_H) \
flags.h toplev.h
hashtable.o: hashtable.c hashtable.h $(CONFIG_H) $(SYSTEM_H) $(OBSTACK_H)
ggc-none.o: ggc-none.c $(GCONFIG_H) $(SYSTEM_H) $(GGC_H)
$(CC) -c $(ALL_CFLAGS) -DGENERATOR_FILE $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
@ -1890,9 +1892,9 @@ PREPROCESSOR_DEFINES = \
LIBCPP_OBJS = cpplib.o cpplex.o cppmacro.o cppexp.o cppfiles.o \
cpphash.o cpperror.o cppinit.o cppdefault.o \
mkdeps.o prefix.o version.o mbchar.o
hashtable.o mkdeps.o prefix.o version.o mbchar.o
LIBCPP_DEPS = cpplib.h cpphash.h intl.h $(SYSTEM_H)
LIBCPP_DEPS = cpplib.h cpphash.h hashtable.h intl.h $(OBSTACK_H) $(SYSTEM_H)
# Most of the other archives built/used by this makefile are for
# targets. This one is strictly for the host.
@ -1911,8 +1913,8 @@ cpperror.o: cpperror.c $(CONFIG_H) $(LIBCPP_DEPS)
cppexp.o: cppexp.c $(CONFIG_H) $(LIBCPP_DEPS)
cpplex.o: cpplex.c $(CONFIG_H) $(LIBCPP_DEPS) mbchar.h
cppmacro.o: cppmacro.c $(CONFIG_H) $(LIBCPP_DEPS)
cpplib.o: cpplib.c $(CONFIG_H) $(LIBCPP_DEPS) $(OBSTACK_H)
cpphash.o: cpphash.c $(CONFIG_H) $(LIBCPP_DEPS) $(OBSTACK_H)
cpplib.o: cpplib.c $(CONFIG_H) $(LIBCPP_DEPS)
cpphash.o: cpphash.c $(CONFIG_H) $(LIBCPP_DEPS)
cppfiles.o: cppfiles.c $(CONFIG_H) $(LIBCPP_DEPS) $(SPLAY_TREE_H) mkdeps.h
cppinit.o: cppinit.c $(CONFIG_H) $(LIBCPP_DEPS) cppdefault.h \
mkdeps.h prefix.h output.h version.h

View File

@ -23,6 +23,7 @@ Boston, MA 02111-1307, USA. */
#define GCC_C_COMMON_H
#include "splay-tree.h"
#include "cpplib.h"
/* Usage of TREE_LANG_FLAG_?:
0: COMPOUND_STMT_NO_SCOPE (in COMPOUND_STMT).
@ -168,6 +169,17 @@ enum c_tree_index
CTI_MAX
};
#define C_RID_CODE(id) (((struct c_common_identifier *) (id))->rid_code)
/* Identifier part common to the C front ends. Inherits from
tree_identifier, despite appearances. */
struct c_common_identifier
{
struct tree_common common;
struct cpp_hashnode node;
ENUM_BITFIELD(rid) rid_code: CHAR_BIT;
};
#define wchar_type_node c_global_trees[CTI_WCHAR_TYPE]
#define signed_wchar_type_node c_global_trees[CTI_SIGNED_WCHAR_TYPE]
#define unsigned_wchar_type_node c_global_trees[CTI_UNSIGNED_WCHAR_TYPE]

View File

@ -59,7 +59,10 @@ c_post_options ()
static void
c_init_options ()
{
parse_in = cpp_create_reader (CLK_GNUC89);
/* Make identifier nodes long enough for the language-specific slots. */
set_identifier_size (sizeof (struct lang_identifier));
parse_in = cpp_create_reader (ident_hash, CLK_GNUC89);
/* Mark as "unspecified". */
flag_bounds_check = -1;

View File

@ -997,7 +997,12 @@ c_lex (value)
goto retry;
case CPP_NAME:
*value = get_identifier ((const char *) NODE_NAME (tok.val.node));
{
tree node = HT_IDENT_TO_GCC_IDENT (HT_NODE (tok.val.node));
if (TREE_CODE (node) != IDENTIFIER_NODE)
make_identifier (node);
*value = node;
}
break;
case CPP_INT:

View File

@ -61,7 +61,7 @@ extern void init_pragma PARAMS ((void));
/* Duplicate prototypes for the register_pragma stuff and the typedef for
cpp_reader, to avoid dragging cpplib.h in almost everywhere... */
#ifndef __GCC_CPPLIB__
#ifndef GCC_CPPLIB_H
typedef struct cpp_reader cpp_reader;
extern void cpp_register_pragma PARAMS ((cpp_reader *,

View File

@ -36,10 +36,9 @@ Boston, MA 02111-1307, USA. */
struct lang_identifier
{
struct tree_identifier ignore;
struct c_common_identifier ignore;
tree global_value, local_value, label_value, implicit_decl;
tree error_locus, limbo_value;
enum rid rid_code;
};
/* Wrapping c_lang_decl in another struct is an unfortunate
@ -98,8 +97,6 @@ struct lang_decl
and C_RID_YYCODE is the token number wanted by Yacc. */
#define C_IS_RESERVED_WORD(id) TREE_LANG_FLAG_0 (id)
#define C_RID_CODE(id) \
(((struct lang_identifier *) (id))->rid_code)
/* In a RECORD_TYPE, a sorted array of the fields of the type. */
struct lang_type

View File

@ -1,3 +1,10 @@
2001-05-20 Neil Booth <neil@daikokuya.demon.co.uk>
* cp-tree.h (struct lang_identifier, C_RID_YYCODE): Update.
(C_RID_CODE): Remove.
* lex.c (cxx_init_options): Call set_identifier_size. Update.
(init_parse): Don't do it here.
2001-05-18 Diego Novillo <dnovillo@redhat.com>
* decl2.c (finish_objects): Use the original SYMBOL_REF from the

View File

@ -270,13 +270,12 @@ extern int flag_huge_objects;
struct lang_identifier
{
struct tree_identifier ignore;
struct c_common_identifier ignore;
tree namespace_bindings;
tree bindings;
tree class_value;
tree class_template_info;
struct lang_id2 *x;
enum rid rid_code;
};
/* In an IDENTIFIER_NODE, nonzero if this identifier is actually a
@ -284,12 +283,9 @@ struct lang_identifier
and C_RID_YYCODE is the token number wanted by Yacc. */
#define C_IS_RESERVED_WORD(id) TREE_LANG_FLAG_5 (id)
#define C_RID_CODE(id) \
(((struct lang_identifier *) (id))->rid_code)
extern const short rid_to_yy[RID_MAX];
#define C_RID_YYCODE(id) \
rid_to_yy[((struct lang_identifier *) (id))->rid_code]
#define C_RID_YYCODE(id) rid_to_yy[C_RID_CODE (id)]
#define LANG_IDENTIFIER_CAST(NODE) \
((struct lang_identifier*)IDENTIFIER_NODE_CHECK (NODE))
@ -1878,7 +1874,7 @@ struct lang_decl
} u2;
};
#define DEFARG_POINTER(NODE) (DEFAULT_ARG_CHECK(NODE)->identifier.pointer)
#define DEFARG_POINTER(NODE) (DEFAULT_ARG_CHECK(NODE)->identifier.id.str)
/* Non-zero if NODE is a _DECL with TREE_READONLY set. */
#define TREE_READONLY_DECL_P(NODE) \

View File

@ -258,7 +258,10 @@ cxx_post_options ()
static void
cxx_init_options ()
{
parse_in = cpp_create_reader (CLK_GNUCXX);
/* Make identifier nodes long enough for the language-specific slots. */
set_identifier_size (sizeof (struct lang_identifier));
parse_in = cpp_create_reader (ident_hash, CLK_GNUCXX);
/* Default exceptions on. */
flag_exceptions = 1;
@ -696,8 +699,6 @@ const char *
init_parse (filename)
const char *filename;
{
/* Make identifier nodes long enough for the language-specific slots. */
set_identifier_size (sizeof (struct lang_identifier));
decl_printable_name = lang_printable_name;
input_filename = "<internal>";

View File

@ -1,4 +1,4 @@
/* Part of CPP library. (Identifier and string tables.)
/* Hash tables for the CPP library.
Copyright (C) 1986, 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1998,
1999, 2000 Free Software Foundation, Inc.
Written by Per Bothner, 1994.
@ -27,266 +27,95 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "system.h"
#include "cpplib.h"
#include "cpphash.h"
#include "obstack.h"
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
static cpp_hashnode *alloc_node PARAMS ((hash_table *));
/* Initial hash table size. (It can grow if necessary.) This is the
largest prime number smaller than 2**12. */
#define HASHSIZE 4093
/* Return an identifier node for hashtable.c. Used by cpplib except
when integrated with the C front ends. */
/* This is the structure used for the hash table. */
struct htab
static cpp_hashnode *
alloc_node (table)
hash_table *table;
{
struct cpp_hashnode **entries;
size_t size;
size_t nelts;
};
static void expand_hash PARAMS ((struct htab *));
static unsigned long higher_prime_number PARAMS ((unsigned long));
/* Set up and tear down internal structures for macro expansion. */
void
_cpp_init_hashtable (pfile)
cpp_reader *pfile;
{
pfile->hash_ob = xnew (struct obstack);
obstack_init (pfile->hash_ob);
pfile->hashtab = xobnew (pfile->hash_ob, struct htab);
pfile->hashtab->nelts = 0;
pfile->hashtab->size = HASHSIZE;
pfile->hashtab->entries = xcnewvec (cpp_hashnode *, HASHSIZE);
cpp_hashnode *node;
node = obstack_alloc (&table->pfile->hash_ob, sizeof (cpp_hashnode));
memset ((PTR) node, 0, sizeof (cpp_hashnode));
return node;
}
/* Set up the identifier hash table. Use TABLE if non-null, otherwise
create our own. */
void
_cpp_cleanup_hashtable (pfile)
_cpp_init_hashtable (pfile, table)
cpp_reader *pfile;
hash_table *table;
{
cpp_hashnode **p, **limit;
p = pfile->hashtab->entries;
limit = p + pfile->hashtab->size;
do
if (table == NULL)
{
if (*p)
_cpp_free_definition (*p);
pfile->our_hashtable = 1;
table = ht_create (13); /* 8K (=2^13) entries. */
table->alloc_node = (hashnode (*) PARAMS ((hash_table *))) alloc_node;
gcc_obstack_init (&pfile->hash_ob);
}
while (++p < limit);
free (pfile->hashtab->entries);
obstack_free (pfile->hash_ob, 0);
free (pfile->hash_ob);
table->pfile = pfile;
pfile->hash_table = table;
}
/* The code below is a specialization of Vladimir Makarov's expandable
hash tables (see libiberty/hashtab.c). The abstraction penalty was
too high to continue using the generic form. This code knows
intrinsically how to calculate a hash value, and how to compare an
existing entry with a potential new one. Also, the ability to
delete members from the table has been removed. */
/* Tear down the identifier hash table. */
void
_cpp_destroy_hashtable (pfile)
cpp_reader *pfile;
{
if (pfile->our_hashtable)
{
free (pfile->hash_table);
obstack_free (&pfile->hash_ob, 0);
}
}
/* Returns the hash entry for the STR of length LEN, creating one
if necessary. */
cpp_hashnode *
cpp_lookup (pfile, name, len)
cpp_lookup (pfile, str, len)
cpp_reader *pfile;
const U_CHAR *name;
size_t len;
const unsigned char *str;
unsigned int len;
{
size_t n = len;
unsigned int r = 0;
const U_CHAR *str = name;
U_CHAR *dest = _cpp_pool_reserve (&pfile->ident_pool, len + 1);
do
{
r = HASHSTEP (r, *str);
*dest++ = *str++;
}
while (--n);
*dest = '\0';
return _cpp_lookup_with_hash (pfile, len, r);
/* ht_lookup cannot return NULL. */
return CPP_HASHNODE (ht_lookup (pfile->hash_table, str, len, HT_ALLOC));
}
/* NAME is a null-terminated identifier of length len. It is assumed
to have been placed at the front of the identifier pool. */
cpp_hashnode *
_cpp_lookup_with_hash (pfile, len, hash)
/* Determine whether the str STR, of length LEN, is a defined macro. */
int
cpp_defined (pfile, str, len)
cpp_reader *pfile;
size_t len;
unsigned int hash;
const unsigned char *str;
int len;
{
unsigned int index;
size_t size;
cpp_hashnode *entry;
cpp_hashnode **entries;
unsigned char *name = POOL_FRONT (&pfile->ident_pool);
cpp_hashnode *node;
entries = pfile->hashtab->entries;
size = pfile->hashtab->size;
node = CPP_HASHNODE (ht_lookup (pfile->hash_table, str, len, HT_NO_INSERT));
hash += len;
index = hash % size;
entry = entries[index];
if (entry)
{
unsigned int hash2;
if (entry->hash == hash && NODE_LEN (entry) == len
&& !memcmp (NODE_NAME (entry), name, len))
return entry;
hash2 = 1 + hash % (size - 2);
for (;;)
{
index += hash2;
if (index >= size)
index -= size;
entry = entries[index];
if (entry == NULL)
break;
if (entry->hash == hash && NODE_LEN (entry) == len
&& !memcmp (NODE_NAME (entry), name, len))
return entry;
}
}
/* Commit the memory for the identifier. */
POOL_COMMIT (&pfile->ident_pool, len + 1);
/* Create a new hash node and insert it in the table. */
entries[index] = obstack_alloc (pfile->hash_ob, sizeof (cpp_hashnode));
entry = entries[index];
entry->type = NT_VOID;
entry->flags = 0;
entry->directive_index = 0;
entry->arg_index = 0;
NODE_LEN (entry) = len;
entry->hash = hash;
NODE_NAME (entry) = name;
entry->value.macro = 0;
pfile->hashtab->nelts++;
if (size * 3 <= pfile->hashtab->nelts * 4)
expand_hash (pfile->hashtab);
return entry;
/* If it's of type NT_MACRO, it cannot be poisoned. */
return node && node->type == NT_MACRO;
}
static void
expand_hash (htab)
struct htab *htab;
{
cpp_hashnode **oentries;
cpp_hashnode **olimit;
cpp_hashnode **p;
size_t size;
oentries = htab->entries;
olimit = oentries + htab->size;
htab->size = size = higher_prime_number (htab->size * 2);
htab->entries = xcnewvec (cpp_hashnode *, size);
for (p = oentries; p < olimit; p++)
{
if (*p != NULL)
{
unsigned int index;
unsigned int hash, hash2;
cpp_hashnode *entry = *p;
hash = entry->hash;
index = hash % size;
if (htab->entries[index] == NULL)
{
insert:
htab->entries[index] = entry;
continue;
}
hash2 = 1 + hash % (size - 2);
for (;;)
{
index += hash2;
if (index >= size)
index -= size;
if (htab->entries[index] == NULL)
goto insert;
}
}
}
free (oentries);
}
/* The following function returns the nearest prime number which is
greater than a given source number, N. */
static unsigned long
higher_prime_number (n)
unsigned long n;
{
unsigned long i;
/* Ensure we have a larger number and then force to odd. */
n++;
n |= 0x01;
/* All odd numbers < 9 are prime. */
if (n < 9)
return n;
/* Otherwise find the next prime using a sieve. */
next:
for (i = 3; i * i <= n; i += 2)
if (n % i == 0)
{
n += 2;
goto next;
}
return n;
}
/* For all nodes in the hashtable, callback CB with parameters PFILE,
the node, and V. */
void
cpp_forall_identifiers (pfile, cb, v)
cpp_reader *pfile;
int (*cb) PARAMS ((cpp_reader *, cpp_hashnode *, void *));
void *v;
cpp_cb cb;
PTR v;
{
cpp_hashnode **p, **limit;
p = pfile->hashtab->entries;
limit = p + pfile->hashtab->size;
do
{
if (*p)
if ((*cb) (pfile, *p, v) == 0)
break;
}
while (++p < limit);
}
/* Determine whether the identifier ID, of length LEN, is a defined macro. */
int
cpp_defined (pfile, id, len)
cpp_reader *pfile;
const U_CHAR *id;
int len;
{
cpp_hashnode *hp = cpp_lookup (pfile, id, len);
/* If it's of type NT_MACRO, it cannot be poisoned. */
return hp->type == NT_MACRO;
/* We don't need a proxy since the hash table's identifier comes
first in cpp_hashnode. */
ht_forall (pfile->hash_table, (ht_cb) cb, v);
}

View File

@ -19,11 +19,12 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
that need to be visible across files. It's called cpphash.h for
historical reasons. */
#ifndef __GCC_CPPHASH__
#define __GCC_CPPHASH__
#ifndef GCC_CPPHASH_H
#define GCC_CPPHASH_H
struct directive; /* These are deliberately incomplete. */
struct htab;
#include "hashtable.h"
struct directive; /* Deliberately incomplete. */
/* Test if a sign is valid within a preprocessing number. */
#define VALID_SIGN(c, prevc) \
@ -299,9 +300,6 @@ struct cpp_reader
/* Current depth in #include directives. */
unsigned int include_depth;
/* Hash table of macros and assertions. See cpphash.c. */
struct htab *hashtab;
/* Tree of other included files. See cppfiles.c. */
struct splay_tree_s *all_include_files;
@ -318,11 +316,11 @@ struct cpp_reader
/* Obstack holding all macro hash nodes. This never shrinks.
See cpphash.c */
struct obstack *hash_ob;
struct obstack hash_ob;
/* Obstack holding buffer and conditional structures. This is a
real stack. See cpplib.c */
struct obstack *buffer_ob;
real stack. See cpplib.c. */
struct obstack buffer_ob;
/* Pragma table - dynamic, because a library user can add to the
list of recognized pragmas. */
@ -331,6 +329,9 @@ struct cpp_reader
/* Call backs. */
struct cpp_callbacks cb;
/* Identifier hash table. */
struct ht *hash_table;
/* User visible options. */
struct cpp_options opts;
@ -347,6 +348,9 @@ struct cpp_reader
/* Whether to print our version number. Done this way so
we don't get it twice for -v -version. */
unsigned char print_version;
/* Whether cpplib owns the hashtable. */
unsigned char our_hashtable;
};
/* Character classes. Based on the more primitive macros in safe-ctype.h.
@ -384,10 +388,6 @@ extern unsigned char _cpp_trigraph_map[UCHAR_MAX + 1];
#define CPP_PEDANTIC(PF) CPP_OPTION (PF, pedantic)
#define CPP_WTRADITIONAL(PF) CPP_OPTION (PF, warn_traditional)
/* Hash step. The hash calculation is duplicated in cpp_lookup and
parse_name. */
#define HASHSTEP(r, c) ((r) * 67 + (c - 113));
/* In cpperror.c */
enum error_type { WARNING = 0, WARNING_SYSHDR, PEDWARN, ERROR, FATAL, ICE };
extern int _cpp_begin_message PARAMS ((cpp_reader *, enum error_type,
@ -403,10 +403,8 @@ extern void _cpp_push_token PARAMS ((cpp_reader *, const cpp_token *,
const cpp_lexer_pos *));
/* In cpphash.c */
extern void _cpp_init_hashtable PARAMS ((cpp_reader *));
extern void _cpp_cleanup_hashtable PARAMS ((cpp_reader *));
extern cpp_hashnode *_cpp_lookup_with_hash PARAMS ((cpp_reader*, size_t,
unsigned int));
extern void _cpp_init_hashtable PARAMS ((cpp_reader *, hash_table *));
extern void _cpp_destroy_hashtable PARAMS ((cpp_reader *));
/* In cppfiles.c */
extern void _cpp_fake_include PARAMS ((cpp_reader *, const char *));
@ -445,8 +443,7 @@ extern int _cpp_test_assertion PARAMS ((cpp_reader *, int *));
extern int _cpp_handle_directive PARAMS ((cpp_reader *, int));
extern void _cpp_define_builtin PARAMS ((cpp_reader *, const char *));
extern void _cpp_do__Pragma PARAMS ((cpp_reader *));
extern void _cpp_init_stacks PARAMS ((cpp_reader *));
extern void _cpp_cleanup_stacks PARAMS ((cpp_reader *));
extern void _cpp_init_directives PARAMS ((cpp_reader *));
extern void _cpp_init_internal_pragmas PARAMS ((cpp_reader *));
extern void _cpp_do_file_change PARAMS ((cpp_reader *, enum cpp_fc_reason,
const char *, unsigned int));
@ -517,4 +514,4 @@ ufputs (s, f)
return fputs ((const char *)s, f);
}
#endif
#endif /* GCC_CPPHASH_H */

View File

@ -491,7 +491,8 @@ init_library ()
/* Initialize a cpp_reader structure. */
cpp_reader *
cpp_create_reader (lang)
cpp_create_reader (table, lang)
hash_table *table;
enum c_lang lang;
{
struct spec_nodes *s;
@ -536,8 +537,13 @@ cpp_create_reader (lang)
/* Macro pool initially 8K. Aligned, permanent pool. */
_cpp_init_pool (&pfile->macro_pool, 8 * 1024, 0, 0);
_cpp_init_hashtable (pfile);
_cpp_init_stacks (pfile);
/* Initialise the buffer obstack. */
gcc_obstack_init (&pfile->buffer_ob);
/* Initialise the hashtable. */
_cpp_init_hashtable (pfile, table);
_cpp_init_directives (pfile);
_cpp_init_includes (pfile);
_cpp_init_internal_pragmas (pfile);
@ -577,11 +583,10 @@ cpp_destroy (pfile)
}
deps_free (pfile->deps);
obstack_free (&pfile->buffer_ob, 0);
_cpp_destroy_hashtable (pfile);
_cpp_cleanup_includes (pfile);
_cpp_cleanup_stacks (pfile);
_cpp_cleanup_hashtable (pfile);
_cpp_free_lookaheads (pfile);
_cpp_free_pool (&pfile->ident_pool);

View File

@ -479,22 +479,14 @@ parse_identifier (pfile, c)
{
cpp_hashnode *result;
cpp_buffer *buffer = pfile->buffer;
unsigned char *dest, *limit;
unsigned int r = 0, saw_dollar = 0;
dest = POOL_FRONT (&pfile->ident_pool);
limit = POOL_LIMIT (&pfile->ident_pool);
unsigned int saw_dollar = 0, len;
struct obstack *stack = &pfile->hash_table->stack;
do
{
do
{
/* Need room for terminating null. */
if (dest + 1 >= limit)
limit = _cpp_next_chunk (&pfile->ident_pool, 0, &dest);
*dest++ = c;
r = HASHSTEP (r, c);
obstack_1grow (stack, c);
if (c == '$')
saw_dollar++;
@ -524,11 +516,12 @@ parse_identifier (pfile, c)
cpp_pedwarn (pfile, "'$' character(s) in identifier");
/* Identifiers are null-terminated. */
*dest = '\0';
len = obstack_object_size (stack);
obstack_1grow (stack, '\0');
/* This routine commits the memory if necessary. */
result = _cpp_lookup_with_hash (pfile,
dest - POOL_FRONT (&pfile->ident_pool), r);
result = (cpp_hashnode *)
ht_lookup (pfile->hash_table, obstack_finish (stack), len, HT_ALLOCED);
/* Some identifiers require diagnostics when lexed. */
if (result->flags & NODE_DIAGNOSTIC && !pfile->skipping)
@ -1905,7 +1898,8 @@ cpp_interpret_charconst (pfile, token, warn_multi, traditional, pchars_seen)
const unsigned char *limit = str + token->val.str.len;
unsigned int chars_seen = 0;
unsigned int width, max_chars, c;
HOST_WIDE_INT result = 0, mask;
unsigned HOST_WIDE_INT mask;
HOST_WIDE_INT result = 0;
#ifdef MULTIBYTE_CHARS
(void) local_mbtowc (NULL, NULL, 0);

View File

@ -1043,12 +1043,12 @@ do_pragma (pfile)
if (tok.type == CPP_NAME)
{
const cpp_hashnode *node = tok.val.node;
const U_CHAR *name = NODE_NAME (node);
size_t len = NODE_LEN (node);
while (p)
{
if (strlen (p->name) == len && !memcmp (p->name, name, len))
if (strlen (p->name) == len
&& !memcmp (p->name, NODE_NAME (node), len))
{
if (p->isnspace)
{
@ -1403,7 +1403,7 @@ do_endif (pfile)
buffer->if_stack = ifs->next;
buffer->was_skipping = ifs->was_skipping;
obstack_free (pfile->buffer_ob, ifs);
obstack_free (&pfile->buffer_ob, ifs);
}
check_eol (pfile);
@ -1423,7 +1423,7 @@ push_conditional (pfile, skip, type, cmacro)
struct if_stack *ifs;
cpp_buffer *buffer = pfile->buffer;
ifs = xobnew (pfile->buffer_ob, struct if_stack);
ifs = xobnew (&pfile->buffer_ob, struct if_stack);
ifs->pos = pfile->directive_pos;
ifs->next = buffer->if_stack;
ifs->was_skipping = buffer->was_skipping;
@ -1804,7 +1804,7 @@ cpp_push_buffer (pfile, buffer, len, type, filename)
enum cpp_buffer_type type;
const char *filename;
{
cpp_buffer *new = xobnew (pfile->buffer_ob, cpp_buffer);
cpp_buffer *new = xobnew (&pfile->buffer_ob, cpp_buffer);
if (type == BUF_FAKE)
{
@ -1905,22 +1905,17 @@ cpp_pop_buffer (pfile)
buffer->nominal_fname);
}
obstack_free (pfile->buffer_ob, buffer);
obstack_free (&pfile->buffer_ob, buffer);
return pfile->buffer;
}
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
void
_cpp_init_stacks (pfile)
_cpp_init_directives (pfile)
cpp_reader *pfile;
{
unsigned int i;
cpp_hashnode *node;
pfile->buffer_ob = xnew (struct obstack);
obstack_init (pfile->buffer_ob);
/* Register the directives. */
for (i = 0; i < (unsigned int) N_DIRECTIVES; i++)
{
@ -1928,11 +1923,3 @@ _cpp_init_stacks (pfile)
node->directive_index = i + 1;
}
}
void
_cpp_cleanup_stacks (pfile)
cpp_reader *pfile;
{
obstack_free (pfile->buffer_ob, 0);
free (pfile->buffer_ob);
}

View File

@ -20,10 +20,11 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
In other words, you are welcome to use, share and improve this program.
You are forbidden to forbid anyone else to use, share and improve
what you give them. Help stamp out software-hoarding! */
#ifndef __GCC_CPPLIB__
#define __GCC_CPPLIB__
#ifndef GCC_CPPLIB_H
#define GCC_CPPLIB_H
#include <sys/types.h>
#include "hashtable.h"
#ifdef __cplusplus
extern "C" {
@ -45,6 +46,7 @@ typedef struct cpp_callbacks cpp_callbacks;
struct answer;
struct file_name_map_list;
struct ht;
/* The first two groups, apart from '=', can appear in preprocessor
expressions. This allows a lookup table to be implemented in
@ -177,7 +179,7 @@ struct cpp_token
union
{
struct cpp_hashnode *node; /* An identifier. */
cpp_hashnode *node; /* An identifier. */
struct cpp_string str; /* A string, or number. */
unsigned int arg_no; /* Argument no. for a CPP_MACRO_ARG. */
unsigned char c; /* Character represented by CPP_OTHER. */
@ -466,18 +468,22 @@ enum builtin_type
BT_STDC /* `__STDC__' */
};
#define NODE_LEN(NODE) (NODE->len)
#define NODE_NAME(NODE) (NODE->name)
#define CPP_HASHNODE(HNODE) ((cpp_hashnode *) (HNODE))
#define HT_NODE(NODE) ((ht_identifier *) (NODE))
#define NODE_LEN(NODE) HT_LEN (&(NODE)->ident)
#define NODE_NAME(NODE) HT_STR (&(NODE)->ident)
/* The common part of an identifier node shared amongst all 3 C front
ends. Also used to store CPP identifiers, which are a superset of
identifiers in the grammatical sense. */
struct cpp_hashnode
{
const unsigned char *name; /* Null-terminated name. */
unsigned int hash; /* Cached hash value. */
unsigned short len; /* Length of name excluding null. */
struct ht_identifier ident;
unsigned short arg_index; /* Macro argument index. */
unsigned char directive_index; /* Index into directive table. */
ENUM_BITFIELD(node_type) type : 8; /* Node type. */
unsigned char flags; /* Node flags. */
unsigned char rid_code; /* Rid code - for front ends. */
ENUM_BITFIELD(node_type) type : 8; /* CPP node type. */
unsigned char flags; /* CPP flags. */
union
{
@ -488,8 +494,12 @@ struct cpp_hashnode
} value;
};
/* Call this first to get a handle to pass to other functions. */
extern cpp_reader *cpp_create_reader PARAMS ((enum c_lang));
/* Call this first to get a handle to pass to other functions. If you
want cpplib to manage its own hashtable, pass in a NULL pointer.
Or you can pass in an initialised hash table that cpplib will use;
this technique is used by the C front ends. */
extern cpp_reader *cpp_create_reader PARAMS ((struct ht *,
enum c_lang));
/* Call this to release the handle. Any use of the handle after this
function returns is invalid. Returns cpp_errors (pfile). */
@ -593,13 +603,16 @@ extern void cpp_output_token PARAMS ((const cpp_token *, FILE *));
extern const char *cpp_type2name PARAMS ((enum cpp_ttype));
/* In cpphash.c */
/* Lookup an identifier in the hashtable. Puts the identifier in the
table if it is not already there. */
extern cpp_hashnode *cpp_lookup PARAMS ((cpp_reader *,
const unsigned char *, size_t));
const unsigned char *,
unsigned int));
typedef int (*cpp_cb) PARAMS ((cpp_reader *, cpp_hashnode *, void *));
extern void cpp_forall_identifiers PARAMS ((cpp_reader *,
int (*) PARAMS ((cpp_reader *,
cpp_hashnode *,
void *)),
void *));
cpp_cb, void *));
/* In cppmacro.c */
extern void cpp_scan_buffer_nooutput PARAMS ((cpp_reader *, int));
@ -614,4 +627,4 @@ extern void cpp_make_system_header PARAMS ((cpp_reader *, int, int));
#ifdef __cplusplus
}
#endif
#endif /* __GCC_CPPLIB__ */
#endif /* GCC_CPPLIB_H */

View File

@ -1536,7 +1536,8 @@ check_trad_stringification (pfile, macro, string)
{
const cpp_hashnode *node = macro->params[i];
if (NODE_LEN (node) == len && !memcmp (p, NODE_NAME (node), len))
if (NODE_LEN (node) == len
&& !memcmp (p, NODE_NAME (node), len))
{
cpp_warning (pfile,
"macro argument \"%s\" would be stringified with -traditional.",

View File

@ -74,7 +74,7 @@ main (argc, argv)
general_init (argv[0]);
/* Contruct a reader with default language GNU C89. */
pfile = cpp_create_reader (CLK_GNUC89);
pfile = cpp_create_reader (NULL, CLK_GNUC89);
options = cpp_get_options (pfile);
do_preprocessing (argc, argv);

View File

@ -621,7 +621,7 @@ read_scan_file (in_fname, argc, argv)
obstack_init (&scan_file_obstack);
scan_in = cpp_create_reader (CLK_GNUC89);
scan_in = cpp_create_reader (NULL, CLK_GNUC89);
cb = cpp_get_callbacks (scan_in);
cb->file_change = cb_file_change;

View File

@ -146,7 +146,7 @@ extern int warn_cast_align;
characters. The value N is in `id_clash_len'. */
extern int warn_id_clash;
extern int id_clash_len;
extern unsigned int id_clash_len;
/* Nonzero means warn about any objects definitions whose size is larger
than N bytes. Also want about function definitions whose returned

View File

@ -84,6 +84,13 @@ extern void ggc_mark_rtvec_children PARAMS ((struct rtvec_def *));
VARRAY_PUSH_TREE (ggc_pending_trees, t__); \
} while (0)
#define ggc_mark_nonnull_tree(EXPR) \
do { \
tree t__ = (EXPR); \
if (! ggc_set_mark (t__)) \
VARRAY_PUSH_TREE (ggc_pending_trees, t__); \
} while (0)
#define ggc_mark_rtvec(EXPR) \
do { \
rtvec v__ = (EXPR); \

315
gcc/hashtable.c Normal file
View File

@ -0,0 +1,315 @@
/* Hash tables.
Copyright (C) 2000, 2001 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
In other words, you are welcome to use, share and improve this program.
You are forbidden to forbid anyone else to use, share and improve
what you give them. Help stamp out software-hoarding! */
#include "config.h"
#include "system.h"
#include "hashtable.h"
/* The code below is a specialization of Vladimir Makarov's expandable
hash tables (see libiberty/hashtab.c). The abstraction penalty was
too high to continue using the generic form. This code knows
intrinsically how to calculate a hash value, and how to compare an
existing entry with a potential new one. Also, the ability to
delete members from the table has been removed. */
static unsigned int calc_hash PARAMS ((const unsigned char *, unsigned int));
static void ht_expand PARAMS ((hash_table *));
/* Let particular systems override the size of a chunk. */
#ifndef OBSTACK_CHUNK_SIZE
#define OBSTACK_CHUNK_SIZE 0
#endif
/* Let them override the alloc and free routines too. */
#ifndef OBSTACK_CHUNK_ALLOC
#define OBSTACK_CHUNK_ALLOC xmalloc
#endif
#ifndef OBSTACK_CHUNK_FREE
#define OBSTACK_CHUNK_FREE free
#endif
/* Initialise an obstack. */
void
gcc_obstack_init (obstack)
struct obstack *obstack;
{
_obstack_begin (obstack, OBSTACK_CHUNK_SIZE, 0,
(void *(*) PARAMS ((long))) OBSTACK_CHUNK_ALLOC,
(void (*) PARAMS ((void *))) OBSTACK_CHUNK_FREE);
}
/* Calculate the hash of the string STR of length LEN. */
static unsigned int
calc_hash (str, len)
const unsigned char *str;
unsigned int len;
{
unsigned int n = len;
unsigned int r = 0;
#define HASHSTEP(r, c) ((r) * 67 + (c - 113));
while (n--)
r = HASHSTEP (r, *str++);
return r + len;
#undef HASHSTEP
}
/* Initialize an identifier hashtable. */
hash_table *
ht_create (order)
unsigned int order;
{
unsigned int nslots = 1 << order;
hash_table *table;
table = (hash_table *) xmalloc (sizeof (hash_table));
memset (table, 0, sizeof (hash_table));
/* Strings need no alignment. */
gcc_obstack_init (&table->stack);
obstack_alignment_mask (&table->stack) = 0;
table->entries = (hashnode *) xcalloc (nslots, sizeof (hashnode));
table->nslots = nslots;
return table;
}
/* Returns the hash entry for the a STR of length LEN. If that string
already exists in the table, returns the existing entry, and, if
INSERT is CPP_ALLOCED, frees the last obstack object. If the
identifier hasn't been seen before, and INSERT is CPP_NO_INSERT,
returns NULL. Otherwise insert and returns a new entry. A new
string is alloced if INSERT is CPP_ALLOC, otherwise INSERT is
CPP_ALLOCED and the item is assumed to be at the top of the
obstack. */
hashnode
ht_lookup (table, str, len, insert)
hash_table *table;
const unsigned char *str;
unsigned int len;
enum ht_lookup_option insert;
{
unsigned int hash = calc_hash (str, len);
unsigned int hash2;
unsigned int index;
size_t sizemask;
hashnode node;
sizemask = table->nslots - 1;
index = hash & sizemask;
/* hash2 must be odd, so we're guaranteed to visit every possible
location in the table during rehashing. */
hash2 = ((hash * 17) & sizemask) | 1;
table->searches++;
for (;;)
{
node = table->entries[index];
if (node == NULL)
break;
if (HT_LEN (node) == len && !memcmp (HT_STR (node), str, len))
{
if (insert == HT_ALLOCED)
/* The string we search for was placed at the end of the
obstack. Release it. */
obstack_free (&table->stack, (PTR) str);
return node;
}
index = (index + hash2) & sizemask;
table->collisions++;
}
if (insert == HT_NO_INSERT)
return NULL;
node = (*table->alloc_node) (table);
table->entries[index] = node;
HT_LEN (node) = len;
if (insert == HT_ALLOC)
HT_STR (node) = obstack_copy (&table->stack, str, len + 1);
else
HT_STR (node) = str;
if (++table->nelements * 4 >= table->nslots * 3)
/* Must expand the string table. */
ht_expand (table);
return node;
}
/* Double the size of a hash table, re-hashing existing entries. */
static void
ht_expand (table)
hash_table *table;
{
hashnode *nentries, *p, *limit;
unsigned int size, sizemask;
size = table->nslots * 2;
nentries = (hashnode *) xcalloc (size, sizeof (hashnode));
sizemask = size - 1;
p = table->entries;
limit = p + table->nslots;
do
if (*p)
{
unsigned int index, hash, hash2;
hash = calc_hash (HT_STR (*p), HT_LEN (*p));
hash2 = ((hash * 17) & sizemask) | 1;
index = hash & sizemask;
for (;;)
{
if (! nentries[index])
{
nentries[index] = *p;
break;
}
index = (index + hash2) & sizemask;
}
}
while (++p < limit);
free (table->entries);
table->entries = nentries;
table->nslots = size;
}
/* For all nodes in TABLE, callback CB with parameters TABLE->PFILE,
the node, and V. */
void
ht_forall (table, cb, v)
hash_table *table;
ht_cb cb;
const PTR v;
{
hashnode *p, *limit;
p = table->entries;
limit = p + table->nslots;
do
if (*p)
{
if ((*cb) (table->pfile, *p, v) == 0)
break;
}
while (++p < limit);
}
/* Dump allocation statistics to stderr. */
void
ht_dump_statistics (table)
hash_table *table;
{
size_t nelts, nids, overhead, headers;
size_t total_bytes, longest, sum_of_squares;
double exp_len, exp_len2, exp2_len;
hashnode *p, *limit;
#define SCALE(x) ((unsigned long) ((x) < 1024*10 \
? (x) \
: ((x) < 1024*1024*10 \
? (x) / 1024 \
: (x) / (1024*1024))))
#define LABEL(x) ((x) < 1024*10 ? ' ' : ((x) < 1024*1024*10 ? 'k' : 'M'))
total_bytes = longest = sum_of_squares = nids = 0;
p = table->entries;
limit = p + table->nslots;
do
if (*p)
{
size_t n = HT_LEN (*p);
total_bytes += n;
sum_of_squares += n * n;
if (n > longest)
longest = n;
nids++;
}
while (++p < limit);
nelts = table->nelements;
overhead = obstack_memory_used (&table->stack) - total_bytes;
headers = table->nslots * sizeof (hashnode);
fprintf (stderr, "\nString pool\nentries\t\t%lu\n",
(unsigned long) nelts);
fprintf (stderr, "identifiers\t%lu (%.2f%%)\n",
(unsigned long) nids, nids * 100.0 / nelts);
fprintf (stderr, "slots\t\t%lu\n",
(unsigned long) table->nslots);
fprintf (stderr, "bytes\t\t%lu%c (%lu%c overhead)\n",
SCALE (total_bytes), LABEL (total_bytes),
SCALE (overhead), LABEL (overhead));
fprintf (stderr, "table size\t%lu%c\n",
SCALE (headers), LABEL (headers));
exp_len = (double)total_bytes / (double)nelts;
exp2_len = exp_len * exp_len;
exp_len2 = (double) sum_of_squares / (double) nelts;
fprintf (stderr, "coll/search\t%.4f\n",
(double) table->collisions / (double) table->searches);
fprintf (stderr, "ins/search\t%.4f\n",
(double) nelts / (double) table->searches);
fprintf (stderr, "avg. entry\t%.2f bytes (+/- %.2f)\n",
exp_len, approx_sqrt (exp_len2 - exp2_len));
fprintf (stderr, "longest entry\t%lu\n",
(unsigned long) longest);
#undef SCALE
#undef LABEL
}
/* Return the approximate positive square root of a number N. This is for
statistical reports, not code generation. */
double
approx_sqrt (x)
double x;
{
double s, d;
if (x < 0)
abort ();
if (x == 0)
return 0;
s = x;
do
{
d = (s * s - x) / (2 * s);
s -= d;
}
while (d > .0001);
return s;
}

85
gcc/hashtable.h Normal file
View File

@ -0,0 +1,85 @@
/* Hash tables.
Copyright (C) 2000, 2001 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#ifndef GCC_HASHTABLE_H
#define GCC_HASHTABLE_H
#include "obstack.h"
/* This is what each hash table entry points to. It may be embedded
deeply within another object. */
typedef struct ht_identifier ht_identifier;
struct ht_identifier
{
unsigned int len;
const unsigned char *str;
};
#define HT_LEN(NODE) ((NODE)->len)
#define HT_STR(NODE) ((NODE)->str)
/* We want code outside cpplib, such as the compiler front-ends, to be
able to include this header, and to be able to link with
cpphashtbl.o without pulling in any other parts of cpplib. */
struct cpp_reader;
typedef struct ht hash_table;
typedef struct ht_identifier *hashnode;
enum ht_lookup_option {HT_NO_INSERT = 0, HT_ALLOC, HT_ALLOCED};
/* An identifier hash table for cpplib and the front ends. */
struct ht
{
/* Identifiers are allocated from here. */
struct obstack stack;
hashnode *entries;
/* Call back. */
hashnode (*alloc_node) PARAMS ((hash_table *));
unsigned int nslots; /* Total slots in the entries array. */
unsigned int nelements; /* Number of live elements. */
/* Link to reader, if any. For the benefit of cpplib. */
struct cpp_reader *pfile;
/* Table usage statistics. */
unsigned int searches;
unsigned int collisions;
};
extern void gcc_obstack_init PARAMS ((struct obstack *));
/* Initialise the hashtable with 2 ^ order entries. */
extern hash_table *ht_create PARAMS ((unsigned int order));
extern hashnode ht_lookup PARAMS ((hash_table *, const unsigned char *,
unsigned int, enum ht_lookup_option));
/* For all nodes in TABLE, make a callback. The callback takes
TABLE->PFILE, the node, and a PTR, and the callback sequence stops
if the callback returns zero. */
typedef int (*ht_cb) PARAMS ((struct cpp_reader *, hashnode, const void *));
extern void ht_forall PARAMS ((hash_table *, ht_cb, const void *));
/* Dump allocation statistics to stderr. */
extern void ht_dump_statistics PARAMS ((hash_table *));
/* Approximate positive square root of a host double. This is for
statistical reports, not code generation. */
extern double approx_sqrt PARAMS ((double));
#endif /* GCC_HASHTABLE_H */

View File

@ -727,7 +727,10 @@ generate_struct_by_value_array ()
static void
objc_init_options ()
{
parse_in = cpp_create_reader (CLK_OBJC);
/* Make identifier nodes long enough for the language-specific slots. */
set_identifier_size (sizeof (struct lang_identifier));
parse_in = cpp_create_reader (ident_hash, CLK_OBJC);
c_language = clk_objective_c;
}

View File

@ -1,5 +1,5 @@
/* String pool for GCC.
Copyright (C) 2000 Free Software Foundation, Inc.
Copyright (C) 2000, 2001 Free Software Foundation, Inc.
This file is part of GNU CC.
@ -18,25 +18,25 @@ along with GNU CC; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
/* String pool allocator. All strings allocated by ggc_alloc_string are
uniquified and stored in an obstack which is never shrunk. You can
associate a tree with a string if you wish; this is used to implement
get_identifier.
/* String text, identifer text and identifier node allocator. Strings
allocated by ggc_alloc_string are stored in an obstack which is
never shrunk. Identifiers are uniquely stored in a hash table.
We have our own private hash table implementation which is similar
to the one in cpphash.c (actually, it's a further refinement of
that code). libiberty's hashtab.c is not used because it requires
100% average space overhead per string, which is unacceptable.
Also, this algorithm is faster. */
We have our own private hash table implementation. libiberty's
hashtab.c is not used because it requires 100% average space
overhead per string, which is unacceptable. Also, this algorithm
is faster. */
#include "config.h"
#include "system.h"
#include "ggc.h"
#include "tree.h"
#include "obstack.h"
#include "hashtable.h"
#include "flags.h"
#include "toplev.h"
#define IS_FE_IDENT(NODE) (TREE_CODE (NODE) == IDENTIFIER_NODE)
/* The "" allocated string. */
const char empty_string[] = "";
@ -47,194 +47,33 @@ const char digit_vector[] = {
'5', 0, '6', 0, '7', 0, '8', 0, '9', 0
};
struct ht *ident_hash;
static struct obstack string_stack;
/* Each hashnode is just a pointer to a TREE_IDENTIFIER. */
typedef struct tree_identifier *sp_hashnode;
#define SP_EMPTY(NODE) ((NODE) == NULL)
#define SP_LEN(NODE) ((NODE)->length)
#define SP_TREE(NODE) ((tree) NODE)
#define SP_STR(NODE) ((NODE)->pointer)
#define SP_VALID(NODE) (TREE_CODE (SP_TREE (NODE)) == IDENTIFIER_NODE)
/* This is the hash table structure. There's only one. */
struct str_hash
{
sp_hashnode *entries;
size_t nslots; /* total slots in the entries array */
size_t nelements; /* number of live elements */
/* table usage statistics */
unsigned int searches;
unsigned int collisions;
};
#define INITIAL_HASHSIZE (16*1024)
static struct str_hash string_hash = { 0, INITIAL_HASHSIZE, 0, 0, 0 };
enum insert_option { INSERT, NO_INSERT };
static sp_hashnode alloc_ident PARAMS ((const char *, size_t,
enum insert_option));
static inline unsigned int calc_hash PARAMS ((const unsigned char *, size_t));
static void mark_string_hash PARAMS ((void *));
static void expand_string_table PARAMS ((void));
/* Convenience macro for iterating over the hash table. E is set to
each live entry in turn. */
#define FORALL_IDS(E) \
for (E = string_hash.entries; E < string_hash.entries+string_hash.nslots; E++) \
if (!SP_EMPTY (*E) && SP_VALID (*E))
/* 0 while creating built-in identifiers. */
static int do_identifier_warnings;
static hashnode alloc_node PARAMS ((hash_table *));
static int mark_ident PARAMS ((struct cpp_reader *, hashnode, const PTR));
static void mark_ident_hash PARAMS ((void *));
static int scan_for_clashes PARAMS ((struct cpp_reader *, hashnode,
const char *));
/* Initialize the string pool. */
void
init_stringpool ()
{
/* Create with 16K (2^14) entries. */
ident_hash = ht_create (14);
ident_hash->alloc_node = alloc_node;
gcc_obstack_init (&string_stack);
ggc_add_root (&string_hash, 1, sizeof string_hash, mark_string_hash);
/* Strings need no alignment. */
obstack_alignment_mask (&string_stack) = 0;
string_hash.entries = (sp_hashnode *)
xcalloc (string_hash.nslots, sizeof (sp_hashnode));
ggc_add_root (&ident_hash, 1, sizeof ident_hash, mark_ident_hash);
}
/* Enable warnings on similar identifiers (if requested).
Done after the built-in identifiers are created. */
void
start_identifier_warnings ()
/* Allocate a hash node. */
static hashnode
alloc_node (table)
hash_table *table ATTRIBUTE_UNUSED;
{
do_identifier_warnings = 1;
}
/* Record the size of an identifier node for the language in use.
SIZE is the total size in bytes.
This is called by the language-specific files. This must be
called before allocating any identifiers. */
void
set_identifier_size (size)
int size;
{
tree_code_length[(int) IDENTIFIER_NODE]
= (size - sizeof (struct tree_common)) / sizeof (tree);
}
/* Calculate the hash of the string STR, which is of length LEN. */
static inline unsigned int
calc_hash (str, len)
const unsigned char *str;
size_t len;
{
size_t n = len;
unsigned int r = 0;
#define HASHSTEP(r, c) ((r) * 67 + (c - 113));
while (n--)
r = HASHSTEP (r, *str++);
return r + len;
#undef HASHSTEP
}
/* Internal primitive: returns the header structure for the identifier
of length LENGTH, containing CONTENTS. If that identifier already
exists in the table, returns the existing entry. If the identifier
hasn't been seen before and the last argument is INSERT, inserts
and returns a new entry. Otherwise returns NULL. */
static sp_hashnode
alloc_ident (contents, length, insert)
const char *contents;
size_t length;
enum insert_option insert;
{
unsigned int hash = calc_hash ((const unsigned char *)contents, length);
unsigned int hash2;
unsigned int index;
size_t sizemask;
sp_hashnode entry;
sizemask = string_hash.nslots - 1;
index = hash & sizemask;
/* hash2 must be odd, so we're guaranteed to visit every possible
location in the table during rehashing. */
hash2 = ((hash * 17) & sizemask) | 1;
string_hash.searches++;
for (;;)
{
entry = string_hash.entries[index];
if (SP_EMPTY (entry))
break;
if ((size_t) SP_LEN (entry) == length
&& !memcmp (SP_STR (entry), contents, length))
return entry;
index = (index + hash2) & sizemask;
string_hash.collisions++;
}
if (insert == NO_INSERT)
return NULL;
entry = (sp_hashnode) make_node (IDENTIFIER_NODE);
string_hash.entries[index] = entry;
SP_STR (entry) = ggc_alloc_string (contents, length);
SP_LEN (entry) = length;
/* This is not yet an identifier. */
TREE_SET_CODE (entry, ERROR_MARK);
if (++string_hash.nelements * 4 >= string_hash.nslots * 3)
/* Must expand the string table. */
expand_string_table ();
return entry;
}
/* Subroutine of alloc_ident which doubles the size of the hash table
and rehashes all the strings into the new table. Returns the entry
in the new table corresponding to ENTRY. */
static void
expand_string_table ()
{
sp_hashnode *nentries;
sp_hashnode *e;
size_t size, sizemask;
size = string_hash.nslots * 2;
nentries = (sp_hashnode *) xcalloc (size, sizeof (sp_hashnode));
sizemask = size - 1;
FORALL_IDS (e)
{
unsigned int index, hash, hash2;
hash = calc_hash ((const unsigned char *) SP_STR (*e), SP_LEN (*e));
hash2 = ((hash * 17) & sizemask) | 1;
index = hash & sizemask;
for (;;)
{
if (SP_EMPTY (nentries[index]))
{
nentries[index] = *e;
break;
}
index = (index + hash2) & sizemask;
}
}
free (string_hash.entries);
string_hash.entries = nentries;
string_hash.nslots = size;
return GCC_IDENT_TO_HT_IDENT (make_node (IDENTIFIER_NODE));
}
/* Allocate and return a string constant of length LENGTH, containing
@ -260,43 +99,40 @@ ggc_alloc_string (contents, length)
return obstack_finish (&string_stack);
}
/* NODE is an identifier known to the preprocessor. Make it known to
the front ends as well. */
void
make_identifier (node)
tree node;
{
/* If this identifier is longer than the clash-warning length,
do a brute force search of the entire table for clashes. */
if (warn_id_clash && do_identifier_warnings
&& IDENTIFIER_LENGTH (node) >= id_clash_len)
ht_forall (ident_hash, (ht_cb) scan_for_clashes,
IDENTIFIER_POINTER (node));
TREE_SET_CODE (node, IDENTIFIER_NODE);
#ifdef GATHER_STATISTICS
id_string_size += IDENTIFIER_LENGTH (node);
#endif
}
/* Return an IDENTIFIER_NODE whose name is TEXT (a null-terminated string).
If an identifier with that name has previously been referred to,
the same node is returned this time. */
tree
get_identifier (text)
const char *text;
{
sp_hashnode node;
size_t length = strlen (text);
hashnode ht_node = ht_lookup (ident_hash,
(const unsigned char *) text,
strlen (text), HT_ALLOC);
node = alloc_ident (text, length, INSERT);
if (!SP_VALID (node))
{
/* If this identifier is longer than the clash-warning length,
do a brute force search of the entire table for clashes. */
if (warn_id_clash && do_identifier_warnings && length >= (size_t) id_clash_len)
{
sp_hashnode *e;
FORALL_IDS (e)
{
if (SP_LEN (*e) >= id_clash_len
&& !strncmp (SP_STR (*e), text, id_clash_len))
{
warning ("\"%s\" and \"%s\" identical in first %d characters",
text, SP_STR (*e), id_clash_len);
break;
}
}
}
TREE_SET_CODE (node, IDENTIFIER_NODE);
#ifdef GATHER_STATISTICS
id_string_size += length;
#endif
}
return SP_TREE (node);
/* ht_node can't be NULL here. */
return HT_IDENT_TO_GCC_IDENT (ht_node);
}
/* If an identifier with the name TEXT (a null-terminated string) has
@ -307,90 +143,92 @@ tree
maybe_get_identifier (text)
const char *text;
{
sp_hashnode node;
hashnode ht_node;
tree node;
size_t length = strlen (text);
node = alloc_ident (text, length, NO_INSERT);
if (!SP_EMPTY (node) && SP_VALID (node))
return SP_TREE (node);
ht_node = ht_lookup (ident_hash, (const unsigned char *) text,
length, HT_NO_INSERT);
if (ht_node)
{
node = HT_IDENT_TO_GCC_IDENT (ht_node);
if (IS_FE_IDENT (node))
return node;
}
return NULL_TREE;
}
/* If this identifier is longer than the clash-warning length,
do a brute force search of the entire table for clashes. */
static int
scan_for_clashes (pfile, h, text)
struct cpp_reader *pfile ATTRIBUTE_UNUSED;
hashnode h;
const char *text;
{
tree node = HT_IDENT_TO_GCC_IDENT (h);
if (IS_FE_IDENT (node)
&& IDENTIFIER_LENGTH (node) >= id_clash_len
&& !memcmp (IDENTIFIER_POINTER (node), text, id_clash_len))
{
warning ("\"%s\" and \"%s\" identical in first %d characters",
text, IDENTIFIER_POINTER (node), id_clash_len);
return 0;
}
return 1;
}
/* Record the size of an identifier node for the language in use.
SIZE is the total size in bytes.
This is called by the language-specific files. This must be
called before allocating any identifiers. */
void
set_identifier_size (size)
int size;
{
tree_code_length[(int) IDENTIFIER_NODE]
= (size - sizeof (struct tree_common)) / sizeof (tree);
}
/* Enable warnings on similar identifiers (if requested).
Done after the built-in identifiers are created. */
void
start_identifier_warnings ()
{
do_identifier_warnings = 1;
}
/* Report some basic statistics about the string pool. */
void
stringpool_statistics ()
{
size_t nelts, nids, overhead, headers;
size_t total_bytes, longest, sum_of_squares;
double exp_len, exp_len2, exp2_len;
sp_hashnode *e;
#define SCALE(x) ((unsigned long) ((x) < 1024*10 \
? (x) \
: ((x) < 1024*1024*10 \
? (x) / 1024 \
: (x) / (1024*1024))))
#define LABEL(x) ((x) < 1024*10 ? ' ' : ((x) < 1024*1024*10 ? 'k' : 'M'))
total_bytes = longest = sum_of_squares = nids = 0;
FORALL_IDS (e)
{
size_t n = SP_LEN (*e);
total_bytes += n;
sum_of_squares += n*n;
if (n > longest)
longest = n;
if (SP_VALID (*e))
nids++;
}
nelts = string_hash.nelements;
overhead = obstack_memory_used (&string_stack) - total_bytes;
headers = string_hash.nslots * sizeof (sp_hashnode);
fprintf (stderr,
"\nString pool\n\
entries\t\t%lu\n\
identifiers\t%lu (%.2f%%)\n\
slots\t\t%lu\n\
bytes\t\t%lu%c (%lu%c overhead)\n\
table size\t%lu%c\n",
(unsigned long) nelts,
(unsigned long) nids, nids * 100.0 / nelts,
(unsigned long) string_hash.nslots,
SCALE (total_bytes), LABEL (total_bytes),
SCALE (overhead), LABEL (overhead),
SCALE (headers), LABEL (headers));
exp_len = (double)total_bytes / (double)nelts;
exp2_len = exp_len * exp_len;
exp_len2 = (double)sum_of_squares / (double)nelts;
fprintf (stderr,
"coll/search\t%.4f\n\
ins/search\t%.4f\n\
avg. entry\t%.2f bytes (+/- %.2f)\n\
longest entry\t%lu\n",
(double) string_hash.collisions / (double) string_hash.searches,
(double) nelts / (double) string_hash.searches,
exp_len, approx_sqrt (exp_len2 - exp2_len),
(unsigned long) longest);
#undef SCALE
#undef LABEL
ht_dump_statistics (ident_hash);
}
/* Mark the string hash for GC. */
/* Mark an identifier for GC. */
static int
mark_ident (pfile, h, v)
struct cpp_reader *pfile ATTRIBUTE_UNUSED;
hashnode h;
const PTR v ATTRIBUTE_UNUSED;
{
ggc_mark_nonnull_tree (HT_IDENT_TO_GCC_IDENT (h));
return 1;
}
/* Mark all identifiers for GC. */
static void
mark_string_hash (arg)
void *arg ATTRIBUTE_UNUSED;
mark_ident_hash (arg)
PTR arg ATTRIBUTE_UNUSED;
{
sp_hashnode *h;
FORALL_IDS (h)
{
ggc_mark_tree (SP_TREE (*h));
}
ht_forall (ident_hash, mark_ident, NULL);
}

View File

@ -1421,7 +1421,7 @@ int warn_cast_align;
characters. The value N is in `id_clash_len'. */
int warn_id_clash;
int id_clash_len;
unsigned int id_clash_len;
/* Nonzero means warn about any objects definitions whose size is larger
than N bytes. Also want about function definitions whose returned
@ -1612,29 +1612,6 @@ floor_log2_wide (x)
return log;
}
/* Return the approximate positive square root of a number N. This is for
statistical reports, not code generation. */
double
approx_sqrt (x)
double x;
{
double s, d;
if (x < 0)
abort ();
if (x == 0)
return 0;
s = x;
do
{
d = (s * s - x) / (2 * s);
s -= d;
}
while (d > .0001);
return s;
}
static int float_handler_set;
int float_handled;
jmp_buf float_handler;

View File

@ -169,6 +169,9 @@ struct lang_hooks
/* Each front end provides its own. */
extern struct lang_hooks lang_hooks;
/* The hashtable, so that the C front ends can pass it to cpplib. */
extern struct ht *ident_hash;
/* These functions can be used by targets to set the flags originally
implied by -ffast-math and -fno-fast-math. */

View File

@ -238,26 +238,6 @@ init_obstacks ()
lang_set_decl_assembler_name = set_decl_assembler_name;
}
void
gcc_obstack_init (obstack)
struct obstack *obstack;
{
/* Let particular systems override the size of a chunk. */
#ifndef OBSTACK_CHUNK_SIZE
#define OBSTACK_CHUNK_SIZE 0
#endif
/* Let them override the alloc and free routines too. */
#ifndef OBSTACK_CHUNK_ALLOC
#define OBSTACK_CHUNK_ALLOC xmalloc
#endif
#ifndef OBSTACK_CHUNK_FREE
#define OBSTACK_CHUNK_FREE free
#endif
_obstack_begin (obstack, OBSTACK_CHUNK_SIZE, 0,
(void *(*) PARAMS ((long))) OBSTACK_CHUNK_ALLOC,
(void (*) PARAMS ((void *))) OBSTACK_CHUNK_FREE);
}
/* Allocate SIZE bytes in the permanent obstack
and return a pointer to them. */

View File

@ -729,16 +729,27 @@ struct tree_complex
union tree_node *imag;
};
#include "hashtable.h"
/* Define fields and accessors for some special-purpose tree nodes. */
#define IDENTIFIER_LENGTH(NODE) (IDENTIFIER_NODE_CHECK (NODE)->identifier.length)
#define IDENTIFIER_POINTER(NODE) (IDENTIFIER_NODE_CHECK (NODE)->identifier.pointer)
#define IDENTIFIER_LENGTH(NODE) \
(IDENTIFIER_NODE_CHECK (NODE)->identifier.id.len)
#define IDENTIFIER_POINTER(NODE) \
((char *) IDENTIFIER_NODE_CHECK (NODE)->identifier.id.str)
/* Translate a hash table identifier pointer to a tree_identifier
pointer, and vice versa. */
#define HT_IDENT_TO_GCC_IDENT(NODE) \
((tree) ((char *) (NODE) - sizeof (struct tree_common)))
#define GCC_IDENT_TO_HT_IDENT(NODE) \
(&((struct tree_identifier *) (NODE))->id)
struct tree_identifier
{
struct tree_common common;
int length;
const char *pointer;
struct ht_identifier id;
};
/* In a TREE_LIST node. */
@ -1947,6 +1958,10 @@ extern tree make_tree_vec PARAMS ((int));
extern tree get_identifier PARAMS ((const char *));
/* NODE is an identifier known to the preprocessor. Make it known to
the front ends as well. */
extern void make_identifier PARAMS ((tree node));
/* If an identifier with the name TEXT (a null-terminated string) has
previously been referred to, return that node; otherwise return
NULL_TREE. */