mirror of git://gcc.gnu.org/git/gcc.git
In gcc/: 2011-10-14 Nicola Pero <nicola.pero@meta-innovation.com>
In gcc/: 2011-10-14 Nicola Pero <nicola.pero@meta-innovation.com> * gengtype.c (files_rules): Added rules for objc/objc-map.h and objc/objc-map.c. In gcc/objc/: 2011-10-14 Nicola Pero <nicola.pero@meta-innovation.com> * objc-map.h: New file. * objc-map.c: New file. * config-lang.in (gtfiles): Added objc-map.h. * Make-lang.in (OBJC_OBJS): Added objc-map.o. (objc/objc-map.o): New rule. (objc/objc-act.o): Depend on objc/objc-map.h. * objc-next-runtime-abi-02.c: Added a TODO comment. * objc-act.c: Include objc-map.h. (nst_method_hash_list, cls_method_hash_list): Removed. (instance_method_map, class_method_map): New. (cls_name_hash_list, als_name_hash_list): Removed. (class_name_map, alias_name_map): Removed. (ivar_offset_hash_list): Removed. (hash_class_name_enter, hash_class_name_lookup, hash_enter, hash_lookup, hash_add_attr, add_method_to_hash_list): Removed. (interface_hash_init): New. (objc_init): Call interface_hash_init. (objc_write_global_declarations): Iterate over class_method_map and instance_method_map instead of cls_method_hash_list and nst_method_hash_list. (objc_declare_alias): Use alias_name_map instead of cls_name_hash_list. (objc_is_class_name): Use class_name_map and alias_name_map instead of cls_name_hash_list and als_name_hash_list. (interface_tuple, interface_htab, hash_interface, eq_interface): Removed. (interface_map): New. (add_class): Renamed to add_interface. Use interface_map instead of interface_htab. (lookup_interface): Use interface_map instead of interface_htab. (check_duplicates): Changed first argument to be a tree, potentially a TREE_VEC, instead of a hash. Changed implementation to match. (lookup_method_in_hash_lists): Use class_method_map and instance_method_map instead of cls_method_hash_list and nst_method_hash_list. (objc_build_selector_expr): Likewise. (hash_func): Removed. (hash_init): Create instance_method_map, class_method_map, class_name_map, and alias_name_map. Do not create nst_method_hash_list, cls_method_hash_list, cls_name_hash_list, als_name_hash_list, and ivar_offset_hash_list. (insert_method_into_method_map): New. (objc_add_method): Use insert_method_into_method_map instead of add_method_to_hash_list. (start_class): Call add_interface instead of add_class. * objc-act.h (cls_name_hash_list, als_name_hash_list, nst_method_hash_list, cls_method_hash_list): Removed. In gcc/objcp/: 2011-10-14 Nicola Pero <nicola.pero@meta-innovation.com> * Make-lang.in (OBJCXX_OBJS): Added objc-map.o. (objcp/objc-map.o): New rule. (objcp/objcp-act.o): Depend on objc/objc-map.h. * config-lang.in (gtfiles): Added objc-map.h. From-SVN: r179965
This commit is contained in:
parent
5e678de8ba
commit
3cc2dd4b7e
|
|
@ -1,3 +1,8 @@
|
|||
2011-10-14 Nicola Pero <nicola.pero@meta-innovation.com>
|
||||
|
||||
* gengtype.c (files_rules): Added rules for objc/objc-map.h and
|
||||
objc/objc-map.c.
|
||||
|
||||
2011-10-14 Paolo Carlini <paolo.carlini@oracle.com>
|
||||
|
||||
PR c++/17212
|
||||
|
|
|
|||
|
|
@ -1817,6 +1817,11 @@ struct file_rule_st files_rules[] = {
|
|||
REG_EXTENDED, NULL_REGEX,
|
||||
"gt-objc-objc-act.h", "objc/objc-act.c", NULL_FRULACT },
|
||||
|
||||
/* objc/objc-map.h gives gt-objc-objc-map.h for objc/objc-map.c ! */
|
||||
{ DIR_PREFIX_REGEX "objc/objc-map\\.h$",
|
||||
REG_EXTENDED, NULL_REGEX,
|
||||
"gt-objc-objc-map.h", "objc/objc-map.c", NULL_FRULACT },
|
||||
|
||||
/* General cases. For header *.h and source *.c files, we need
|
||||
* special actions to handle the language. */
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,54 @@
|
|||
2011-10-14 Nicola Pero <nicola.pero@meta-innovation.com>
|
||||
|
||||
* objc-map.h: New file.
|
||||
* objc-map.c: New file.
|
||||
* config-lang.in (gtfiles): Added objc-map.h.
|
||||
* Make-lang.in (OBJC_OBJS): Added objc-map.o.
|
||||
(objc/objc-map.o): New rule.
|
||||
(objc/objc-act.o): Depend on objc/objc-map.h.
|
||||
* objc-next-runtime-abi-02.c: Added a TODO comment.
|
||||
* objc-act.c: Include objc-map.h.
|
||||
(nst_method_hash_list, cls_method_hash_list): Removed.
|
||||
(instance_method_map, class_method_map): New.
|
||||
(cls_name_hash_list, als_name_hash_list): Removed.
|
||||
(class_name_map, alias_name_map): Removed.
|
||||
(ivar_offset_hash_list): Removed.
|
||||
(hash_class_name_enter, hash_class_name_lookup, hash_enter,
|
||||
hash_lookup, hash_add_attr, add_method_to_hash_list): Removed.
|
||||
(interface_hash_init): New.
|
||||
(objc_init): Call interface_hash_init.
|
||||
(objc_write_global_declarations): Iterate over class_method_map
|
||||
and instance_method_map instead of cls_method_hash_list and
|
||||
nst_method_hash_list.
|
||||
(objc_declare_alias): Use alias_name_map instead of
|
||||
cls_name_hash_list.
|
||||
(objc_is_class_name): Use class_name_map and alias_name_map
|
||||
instead of cls_name_hash_list and als_name_hash_list.
|
||||
(interface_tuple, interface_htab, hash_interface, eq_interface):
|
||||
Removed.
|
||||
(interface_map): New.
|
||||
(add_class): Renamed to add_interface. Use interface_map instead
|
||||
of interface_htab.
|
||||
(lookup_interface): Use interface_map instead of interface_htab.
|
||||
(check_duplicates): Changed first argument to be a tree,
|
||||
potentially a TREE_VEC, instead of a hash. Changed implementation
|
||||
to match.
|
||||
(lookup_method_in_hash_lists): Use class_method_map and
|
||||
instance_method_map instead of cls_method_hash_list and
|
||||
nst_method_hash_list.
|
||||
(objc_build_selector_expr): Likewise.
|
||||
(hash_func): Removed.
|
||||
(hash_init): Create instance_method_map, class_method_map,
|
||||
class_name_map, and alias_name_map. Do not create
|
||||
nst_method_hash_list, cls_method_hash_list, cls_name_hash_list,
|
||||
als_name_hash_list, and ivar_offset_hash_list.
|
||||
(insert_method_into_method_map): New.
|
||||
(objc_add_method): Use insert_method_into_method_map instead of
|
||||
add_method_to_hash_list.
|
||||
(start_class): Call add_interface instead of add_class.
|
||||
* objc-act.h (cls_name_hash_list, als_name_hash_list,
|
||||
nst_method_hash_list, cls_method_hash_list): Removed.
|
||||
|
||||
2011-10-11 Michael Meissner <meissner@linux.vnet.ibm.com>
|
||||
|
||||
* objc-next-runtime-abi-01.c (objc_build_exc_ptr): Delete old
|
||||
|
|
|
|||
|
|
@ -55,7 +55,8 @@ OBJC_OBJS = objc/objc-lang.o objc/objc-act.o \
|
|||
objc/objc-gnu-runtime-abi-01.o \
|
||||
objc/objc-next-runtime-abi-01.o \
|
||||
objc/objc-next-runtime-abi-02.o \
|
||||
objc/objc-encoding.o
|
||||
objc/objc-encoding.o \
|
||||
objc/objc-map.o
|
||||
|
||||
objc_OBJS = $(OBJC_OBJS) cc1obj-checksum.o
|
||||
|
||||
|
|
@ -129,6 +130,7 @@ objc/objc-act.o : objc/objc-act.c \
|
|||
$(HASHTAB_H) $(GIMPLE_H) \
|
||||
$(C_PRAGMA_H) $(C_TARGET_H) \
|
||||
objc/objc-encoding.h \
|
||||
objc/objc-map.h \
|
||||
objc/objc-runtime-hooks.h \
|
||||
objc/objc-runtime-shared-support.h
|
||||
|
||||
|
|
@ -139,6 +141,12 @@ objc/objc-encoding.o : objc/objc-encoding.c \
|
|||
objc/objc-encoding.h \
|
||||
objc/objc-runtime-shared-support.h
|
||||
|
||||
objc/objc-map.o : objc/objc-map.c \
|
||||
$(START_HDRS) \
|
||||
$(GGC_H) $(DIAGNOSTIC_CORE_H) $(FLAGS_H) input.h \
|
||||
$(OBSTACK_H) \
|
||||
objc/objc-map.h
|
||||
|
||||
objc.srcextra:
|
||||
|
||||
#
|
||||
|
|
|
|||
|
|
@ -36,4 +36,4 @@ lang_requires="c"
|
|||
# Order is important. If you change this list, make sure you test
|
||||
# building without C++ as well; that is, remove the gcc/cp directory,
|
||||
# and build with --enable-languages=c,objc.
|
||||
gtfiles="\$(srcdir)/c-family/c-objc.h \$(srcdir)/objc/objc-act.h \$(srcdir)/objc/objc-act.c \$(srcdir)/objc/objc-runtime-shared-support.c \$(srcdir)/objc/objc-gnu-runtime-abi-01.c \$(srcdir)/objc/objc-next-runtime-abi-01.c \$(srcdir)/objc/objc-next-runtime-abi-02.c \$(srcdir)/c-parser.c \$(srcdir)/c-tree.h \$(srcdir)/c-decl.c \$(srcdir)/c-lang.h \$(srcdir)/c-objc-common.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-cppbuiltin.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c"
|
||||
gtfiles="\$(srcdir)/objc/objc-map.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/objc/objc-act.h \$(srcdir)/objc/objc-act.c \$(srcdir)/objc/objc-runtime-shared-support.c \$(srcdir)/objc/objc-gnu-runtime-abi-01.c \$(srcdir)/objc/objc-next-runtime-abi-01.c \$(srcdir)/objc/objc-next-runtime-abi-02.c \$(srcdir)/c-parser.c \$(srcdir)/c-tree.h \$(srcdir)/c-decl.c \$(srcdir)/c-lang.h \$(srcdir)/c-objc-common.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-cppbuiltin.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c"
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "flags.h"
|
||||
#include "langhooks.h"
|
||||
#include "objc-act.h"
|
||||
#include "objc-map.h"
|
||||
#include "input.h"
|
||||
#include "function.h"
|
||||
#include "output.h"
|
||||
|
|
@ -157,27 +158,25 @@ static void objc_generate_cxx_cdtors (void);
|
|||
static void objc_decl_method_attributes (tree*, tree, int);
|
||||
static tree build_keyword_selector (tree);
|
||||
|
||||
/* Hash tables to manage the global pool of method prototypes. */
|
||||
static void hash_init (void);
|
||||
|
||||
hash *nst_method_hash_list = 0;
|
||||
hash *cls_method_hash_list = 0;
|
||||
/* Hash tables to manage the global pool of method prototypes. Each
|
||||
of these maps map a method name (selector) identifier to either a
|
||||
single tree (for methods with a single method prototype) or a
|
||||
TREE_VEC (for methods with multiple method prototypes). */
|
||||
static GTY(()) objc_map_t instance_method_map = 0;
|
||||
static GTY(()) objc_map_t class_method_map = 0;
|
||||
|
||||
/* Hash tables to manage the global pool of class names. */
|
||||
|
||||
hash *cls_name_hash_list = 0;
|
||||
hash *als_name_hash_list = 0;
|
||||
static GTY(()) objc_map_t class_name_map = 0;
|
||||
static GTY(()) objc_map_t alias_name_map = 0;
|
||||
|
||||
hash *ivar_offset_hash_list = 0;
|
||||
|
||||
static void hash_class_name_enter (hash *, tree, tree);
|
||||
static hash hash_class_name_lookup (hash *, tree);
|
||||
|
||||
static hash hash_lookup (hash *, tree);
|
||||
static tree lookup_method (tree, tree);
|
||||
static tree lookup_method_static (tree, tree, int);
|
||||
|
||||
static tree add_class (tree, tree);
|
||||
static void interface_hash_init (void);
|
||||
static tree add_interface (tree, tree);
|
||||
static void add_category (tree, tree);
|
||||
static inline tree lookup_category (tree, tree);
|
||||
|
||||
|
|
@ -207,7 +206,7 @@ static void generate_struct_by_value_array (void) ATTRIBUTE_NORETURN;
|
|||
|
||||
static void mark_referenced_methods (void);
|
||||
static bool objc_type_valid_for_messaging (tree type, bool allow_classes);
|
||||
static tree check_duplicates (hash, int, int);
|
||||
static tree check_duplicates (tree, int, int);
|
||||
|
||||
/*** Private Interface (data) ***/
|
||||
/* Flags for lookup_method_static(). */
|
||||
|
|
@ -380,6 +379,7 @@ objc_init (void)
|
|||
|
||||
/* Set up stuff used by FE parser and all runtimes. */
|
||||
errbuf = XNEWVEC (char, 1024 * 10);
|
||||
interface_hash_init ();
|
||||
hash_init ();
|
||||
objc_encoding_init ();
|
||||
/* ... and then check flags and set-up for the selected runtime ... */
|
||||
|
|
@ -418,19 +418,15 @@ objc_write_global_declarations (void)
|
|||
|
||||
if (warn_selector)
|
||||
{
|
||||
int slot;
|
||||
hash hsh;
|
||||
objc_map_iterator_t i;
|
||||
|
||||
/* Run through the selector hash tables and print a warning for any
|
||||
selector which has multiple methods. */
|
||||
objc_map_iterator_initialize (class_method_map, &i);
|
||||
while (objc_map_iterator_move_to_next (class_method_map, &i))
|
||||
check_duplicates (objc_map_iterator_current_value (class_method_map, i), 0, 1);
|
||||
|
||||
for (slot = 0; slot < SIZEHASHTABLE; slot++)
|
||||
{
|
||||
for (hsh = cls_method_hash_list[slot]; hsh; hsh = hsh->next)
|
||||
check_duplicates (hsh, 0, 1);
|
||||
for (hsh = nst_method_hash_list[slot]; hsh; hsh = hsh->next)
|
||||
check_duplicates (hsh, 0, 0);
|
||||
}
|
||||
objc_map_iterator_initialize (instance_method_map, &i);
|
||||
while (objc_map_iterator_move_to_next (instance_method_map, &i))
|
||||
check_duplicates (objc_map_iterator_current_value (instance_method_map, i), 0, 0);
|
||||
}
|
||||
|
||||
/* TODO: consider an early exit here if either errorcount or sorrycount
|
||||
|
|
@ -3351,8 +3347,7 @@ objc_declare_alias (tree alias_ident, tree class_ident)
|
|||
#ifdef OBJCPLUS
|
||||
pop_lang_context ();
|
||||
#endif
|
||||
hash_class_name_enter (als_name_hash_list, alias_ident,
|
||||
underlying_class);
|
||||
objc_map_put (alias_name_map, alias_ident, underlying_class);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3392,15 +3387,13 @@ objc_declare_class (tree identifier)
|
|||
the TYPE_OBJC_INTERFACE. If later an @interface is found,
|
||||
we'll replace the ident with the interface. */
|
||||
TYPE_OBJC_INTERFACE (record) = identifier;
|
||||
hash_class_name_enter (cls_name_hash_list, identifier, NULL_TREE);
|
||||
objc_map_put (class_name_map, identifier, NULL_TREE);
|
||||
}
|
||||
}
|
||||
|
||||
tree
|
||||
objc_is_class_name (tree ident)
|
||||
{
|
||||
hash target;
|
||||
|
||||
if (ident && TREE_CODE (ident) == IDENTIFIER_NODE)
|
||||
{
|
||||
tree t = identifier_global_value (ident);
|
||||
|
|
@ -3428,16 +3421,17 @@ objc_is_class_name (tree ident)
|
|||
if (lookup_interface (ident))
|
||||
return ident;
|
||||
|
||||
target = hash_class_name_lookup (cls_name_hash_list, ident);
|
||||
if (target)
|
||||
return target->key;
|
||||
{
|
||||
tree target;
|
||||
|
||||
target = hash_class_name_lookup (als_name_hash_list, ident);
|
||||
if (target)
|
||||
{
|
||||
gcc_assert (target->list && target->list->value);
|
||||
return target->list->value;
|
||||
}
|
||||
target = objc_map_get (class_name_map, ident);
|
||||
if (target != OBJC_MAP_NOT_FOUND)
|
||||
return ident;
|
||||
|
||||
target = objc_map_get (alias_name_map, ident);
|
||||
if (target != OBJC_MAP_NOT_FOUND)
|
||||
return target;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -3761,25 +3755,30 @@ objc_generate_write_barrier (tree lhs, enum tree_code modifycode, tree rhs)
|
|||
return result;
|
||||
}
|
||||
|
||||
struct GTY(()) interface_tuple {
|
||||
tree id;
|
||||
tree class_name;
|
||||
};
|
||||
/* Implementation of the table mapping a class name (as an identifier)
|
||||
to a class node. The two public functions for it are
|
||||
lookup_interface() and add_interface(). add_interface() is only
|
||||
used in this file, so we can make it static. */
|
||||
|
||||
static GTY ((param_is (struct interface_tuple))) htab_t interface_htab;
|
||||
static GTY(()) objc_map_t interface_map;
|
||||
|
||||
static hashval_t
|
||||
hash_interface (const void *p)
|
||||
static void
|
||||
interface_hash_init (void)
|
||||
{
|
||||
const struct interface_tuple *d = (const struct interface_tuple *) p;
|
||||
return IDENTIFIER_HASH_VALUE (d->id);
|
||||
interface_map = objc_map_alloc_ggc (200);
|
||||
}
|
||||
|
||||
static int
|
||||
eq_interface (const void *p1, const void *p2)
|
||||
static tree
|
||||
add_interface (tree class_name, tree name)
|
||||
{
|
||||
const struct interface_tuple *d = (const struct interface_tuple *) p1;
|
||||
return d->id == p2;
|
||||
/* Put interfaces on list in reverse order. */
|
||||
TREE_CHAIN (class_name) = interface_chain;
|
||||
interface_chain = class_name;
|
||||
|
||||
/* Add it to the map. */
|
||||
objc_map_put (interface_map, name, class_name);
|
||||
|
||||
return interface_chain;
|
||||
}
|
||||
|
||||
tree
|
||||
|
|
@ -3794,19 +3793,12 @@ lookup_interface (tree ident)
|
|||
return NULL_TREE;
|
||||
|
||||
{
|
||||
struct interface_tuple **slot;
|
||||
tree i = NULL_TREE;
|
||||
tree interface = objc_map_get (interface_map, ident);
|
||||
|
||||
if (interface_htab)
|
||||
{
|
||||
slot = (struct interface_tuple **)
|
||||
htab_find_slot_with_hash (interface_htab, ident,
|
||||
IDENTIFIER_HASH_VALUE (ident),
|
||||
NO_INSERT);
|
||||
if (slot && *slot)
|
||||
i = (*slot)->class_name;
|
||||
}
|
||||
return i;
|
||||
if (interface == OBJC_MAP_NOT_FOUND)
|
||||
return NULL_TREE;
|
||||
else
|
||||
return interface;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -5052,71 +5044,75 @@ build_function_type_for_method (tree return_type, tree method,
|
|||
return ftype;
|
||||
}
|
||||
|
||||
/* The 'method' argument is a tree; this tree could either be a single
|
||||
method, which is returned, or could be a TREE_VEC containing a list
|
||||
of methods. In that case, the first one is returned, and warnings
|
||||
are issued as appropriate. */
|
||||
static tree
|
||||
check_duplicates (hash hsh, int methods, int is_class)
|
||||
check_duplicates (tree method, int methods, int is_class)
|
||||
{
|
||||
tree meth = NULL_TREE;
|
||||
tree first_method;
|
||||
size_t i;
|
||||
|
||||
if (hsh)
|
||||
if (method == NULL_TREE)
|
||||
return NULL_TREE;
|
||||
|
||||
if (TREE_CODE (method) != TREE_VEC)
|
||||
return method;
|
||||
|
||||
/* We have two or more methods with the same name but different
|
||||
types. */
|
||||
first_method = TREE_VEC_ELT (method, 0);
|
||||
|
||||
/* But just how different are those types? If
|
||||
-Wno-strict-selector-match is specified, we shall not complain if
|
||||
the differences are solely among types with identical size and
|
||||
alignment. */
|
||||
if (!warn_strict_selector_match)
|
||||
{
|
||||
meth = hsh->key;
|
||||
|
||||
if (hsh->list)
|
||||
{
|
||||
/* We have two or more methods with the same name but
|
||||
different types. */
|
||||
attr loop;
|
||||
|
||||
/* But just how different are those types? If
|
||||
-Wno-strict-selector-match is specified, we shall not
|
||||
complain if the differences are solely among types with
|
||||
identical size and alignment. */
|
||||
if (!warn_strict_selector_match)
|
||||
{
|
||||
for (loop = hsh->list; loop; loop = loop->next)
|
||||
if (!comp_proto_with_proto (meth, loop->value, 0))
|
||||
goto issue_warning;
|
||||
|
||||
return meth;
|
||||
}
|
||||
|
||||
issue_warning:
|
||||
if (methods)
|
||||
{
|
||||
bool type = TREE_CODE (meth) == INSTANCE_METHOD_DECL;
|
||||
|
||||
warning_at (input_location, 0,
|
||||
"multiple methods named %<%c%E%> found",
|
||||
(is_class ? '+' : '-'),
|
||||
METHOD_SEL_NAME (meth));
|
||||
inform (DECL_SOURCE_LOCATION (meth), "using %<%c%s%>",
|
||||
(type ? '-' : '+'),
|
||||
identifier_to_locale (gen_method_decl (meth)));
|
||||
}
|
||||
else
|
||||
{
|
||||
bool type = TREE_CODE (meth) == INSTANCE_METHOD_DECL;
|
||||
|
||||
warning_at (input_location, 0,
|
||||
"multiple selectors named %<%c%E%> found",
|
||||
(is_class ? '+' : '-'),
|
||||
METHOD_SEL_NAME (meth));
|
||||
inform (DECL_SOURCE_LOCATION (meth), "found %<%c%s%>",
|
||||
(type ? '-' : '+'),
|
||||
identifier_to_locale (gen_method_decl (meth)));
|
||||
}
|
||||
|
||||
for (loop = hsh->list; loop; loop = loop->next)
|
||||
{
|
||||
bool type = TREE_CODE (loop->value) == INSTANCE_METHOD_DECL;
|
||||
|
||||
inform (DECL_SOURCE_LOCATION (loop->value), "also found %<%c%s%>",
|
||||
(type ? '-' : '+'),
|
||||
identifier_to_locale (gen_method_decl (loop->value)));
|
||||
}
|
||||
}
|
||||
for (i = 0; i < TREE_VEC_LENGTH (method); i++)
|
||||
if (!comp_proto_with_proto (first_method, TREE_VEC_ELT (method, i), 0))
|
||||
goto issue_warning;
|
||||
|
||||
return first_method;
|
||||
}
|
||||
return meth;
|
||||
|
||||
issue_warning:
|
||||
if (methods)
|
||||
{
|
||||
bool type = TREE_CODE (first_method) == INSTANCE_METHOD_DECL;
|
||||
|
||||
warning_at (input_location, 0,
|
||||
"multiple methods named %<%c%E%> found",
|
||||
(is_class ? '+' : '-'),
|
||||
METHOD_SEL_NAME (first_method));
|
||||
inform (DECL_SOURCE_LOCATION (first_method), "using %<%c%s%>",
|
||||
(type ? '-' : '+'),
|
||||
identifier_to_locale (gen_method_decl (first_method)));
|
||||
}
|
||||
else
|
||||
{
|
||||
bool type = TREE_CODE (first_method) == INSTANCE_METHOD_DECL;
|
||||
|
||||
warning_at (input_location, 0,
|
||||
"multiple selectors named %<%c%E%> found",
|
||||
(is_class ? '+' : '-'),
|
||||
METHOD_SEL_NAME (first_method));
|
||||
inform (DECL_SOURCE_LOCATION (first_method), "found %<%c%s%>",
|
||||
(type ? '-' : '+'),
|
||||
identifier_to_locale (gen_method_decl (first_method)));
|
||||
}
|
||||
|
||||
for (i = 0; i < TREE_VEC_LENGTH (method); i++)
|
||||
{
|
||||
bool type = TREE_CODE (TREE_VEC_ELT (method, i)) == INSTANCE_METHOD_DECL;
|
||||
|
||||
inform (DECL_SOURCE_LOCATION (TREE_VEC_ELT (method, i)), "also found %<%c%s%>",
|
||||
(type ? '-' : '+'),
|
||||
identifier_to_locale (gen_method_decl (TREE_VEC_ELT (method, i))));
|
||||
}
|
||||
|
||||
return first_method;
|
||||
}
|
||||
|
||||
/* If RECEIVER is a class reference, return the identifier node for
|
||||
|
|
@ -5294,17 +5290,18 @@ objc_build_message_expr (tree receiver, tree message_args)
|
|||
static tree
|
||||
lookup_method_in_hash_lists (tree sel_name, int is_class)
|
||||
{
|
||||
hash method_prototype = NULL;
|
||||
tree method_prototype = OBJC_MAP_NOT_FOUND;
|
||||
|
||||
if (!is_class)
|
||||
method_prototype = hash_lookup (nst_method_hash_list,
|
||||
sel_name);
|
||||
|
||||
if (!method_prototype)
|
||||
method_prototype = objc_map_get (instance_method_map, sel_name);
|
||||
|
||||
if (method_prototype == OBJC_MAP_NOT_FOUND)
|
||||
{
|
||||
method_prototype = hash_lookup (cls_method_hash_list,
|
||||
sel_name);
|
||||
method_prototype = objc_map_get (class_method_map, sel_name);
|
||||
is_class = 1;
|
||||
|
||||
if (method_prototype == OBJC_MAP_NOT_FOUND)
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
return check_duplicates (method_prototype, 1, is_class);
|
||||
|
|
@ -5714,21 +5711,19 @@ objc_build_selector_expr (location_t loc, tree selnamelist)
|
|||
/* Look the selector up in the list of all known class and
|
||||
instance methods (up to this line) to check that the selector
|
||||
exists. */
|
||||
hash hsh;
|
||||
tree method;
|
||||
|
||||
/* First try with instance methods. */
|
||||
hsh = hash_lookup (nst_method_hash_list, selname);
|
||||
method = objc_map_get (instance_method_map, selname);
|
||||
|
||||
/* If not found, try with class methods. */
|
||||
if (!hsh)
|
||||
if (method == OBJC_MAP_NOT_FOUND)
|
||||
{
|
||||
hsh = hash_lookup (cls_method_hash_list, selname);
|
||||
}
|
||||
method = objc_map_get (class_method_map, selname);
|
||||
|
||||
/* If still not found, print out a warning. */
|
||||
if (!hsh)
|
||||
{
|
||||
warning (0, "undeclared selector %qE", selname);
|
||||
/* If still not found, print out a warning. */
|
||||
if (method == OBJC_MAP_NOT_FOUND)
|
||||
warning (0, "undeclared selector %qE", selname);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -5761,131 +5756,99 @@ build_ivar_reference (tree id)
|
|||
return (*runtime.build_ivar_reference) (input_location, base, id);
|
||||
}
|
||||
|
||||
/* Compute a hash value for a given method SEL_NAME. */
|
||||
|
||||
static size_t
|
||||
hash_func (tree sel_name)
|
||||
{
|
||||
const unsigned char *s
|
||||
= (const unsigned char *)IDENTIFIER_POINTER (sel_name);
|
||||
size_t h = 0;
|
||||
|
||||
while (*s)
|
||||
h = h * 67 + *s++ - 113;
|
||||
return h;
|
||||
}
|
||||
|
||||
static void
|
||||
hash_init (void)
|
||||
{
|
||||
nst_method_hash_list = ggc_alloc_cleared_vec_hash (SIZEHASHTABLE);
|
||||
cls_method_hash_list = ggc_alloc_cleared_vec_hash (SIZEHASHTABLE);
|
||||
instance_method_map = objc_map_alloc_ggc (1000);
|
||||
class_method_map = objc_map_alloc_ggc (1000);
|
||||
|
||||
cls_name_hash_list = ggc_alloc_cleared_vec_hash (SIZEHASHTABLE);
|
||||
als_name_hash_list = ggc_alloc_cleared_vec_hash (SIZEHASHTABLE);
|
||||
|
||||
ivar_offset_hash_list = ggc_alloc_cleared_vec_hash (SIZEHASHTABLE);
|
||||
class_name_map = objc_map_alloc_ggc (200);
|
||||
alias_name_map = objc_map_alloc_ggc (200);
|
||||
|
||||
/* Initialize the hash table used to hold the constant string objects. */
|
||||
string_htab = htab_create_ggc (31, string_hash,
|
||||
string_eq, NULL);
|
||||
}
|
||||
|
||||
/* This routine adds sel_name to the hash list. sel_name is a class or alias
|
||||
name for the class. If alias name, then value is its underlying class.
|
||||
If class, the value is NULL_TREE. */
|
||||
|
||||
/* Use the following to add a method to class_method_map or
|
||||
instance_method_map. It will add the method, keyed by the
|
||||
METHOD_SEL_NAME. If the method already exists, but with one or
|
||||
more different prototypes, it will store a TREE_VEC in the map,
|
||||
with the method prototypes in the vector. */
|
||||
static void
|
||||
hash_class_name_enter (hash *hashlist, tree sel_name, tree value)
|
||||
insert_method_into_method_map (bool class_method, tree method)
|
||||
{
|
||||
hash obj;
|
||||
int slot = hash_func (sel_name) % SIZEHASHTABLE;
|
||||
tree method_name = METHOD_SEL_NAME (method);
|
||||
tree existing_entry;
|
||||
objc_map_t map;
|
||||
|
||||
obj = ggc_alloc_hashed_entry ();
|
||||
if (value != NULL_TREE)
|
||||
{
|
||||
/* Save the underlying class for the 'alias' in the hash table */
|
||||
attr obj_attr = ggc_alloc_hashed_attribute ();
|
||||
obj_attr->value = value;
|
||||
obj->list = obj_attr;
|
||||
}
|
||||
if (class_method)
|
||||
map = class_method_map;
|
||||
else
|
||||
obj->list = 0;
|
||||
obj->next = hashlist[slot];
|
||||
obj->key = sel_name;
|
||||
map = instance_method_map;
|
||||
|
||||
hashlist[slot] = obj; /* append to front */
|
||||
/* Check if the method already exists in the map. */
|
||||
existing_entry = objc_map_get (map, method_name);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
Searches in the hash table looking for a match for class or alias name.
|
||||
*/
|
||||
|
||||
static hash
|
||||
hash_class_name_lookup (hash *hashlist, tree sel_name)
|
||||
{
|
||||
hash target;
|
||||
|
||||
target = hashlist[hash_func (sel_name) % SIZEHASHTABLE];
|
||||
|
||||
while (target)
|
||||
/* If not, we simply add it to the map. */
|
||||
if (existing_entry == OBJC_MAP_NOT_FOUND)
|
||||
objc_map_put (map, method_name, method);
|
||||
else
|
||||
{
|
||||
if (sel_name == target->key)
|
||||
return target;
|
||||
tree new_entry;
|
||||
|
||||
/* If an entry already exists, it's more complicated. We'll
|
||||
have to check whether the method prototype is the same or
|
||||
not. */
|
||||
if (TREE_CODE (existing_entry) != TREE_VEC)
|
||||
{
|
||||
/* If the method prototypes are the same, there is nothing
|
||||
to do. */
|
||||
if (comp_proto_with_proto (method, existing_entry, 1))
|
||||
return;
|
||||
|
||||
target = target->next;
|
||||
/* If not, create a vector to store both the method already
|
||||
in the map, and the new one that we are adding. */
|
||||
new_entry = make_tree_vec (2);
|
||||
|
||||
TREE_VEC_ELT (new_entry, 0) = existing_entry;
|
||||
TREE_VEC_ELT (new_entry, 1) = method;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* An entry already exists, and it's already a vector. This
|
||||
means that at least 2 different method prototypes were
|
||||
already found, and we're considering registering yet
|
||||
another one. */
|
||||
size_t i;
|
||||
|
||||
/* Check all the existing prototypes. If any matches the
|
||||
one we need to add, there is nothing to do because it's
|
||||
already there. */
|
||||
for (i = 0; i < TREE_VEC_LENGTH (existing_entry); i++)
|
||||
if (comp_proto_with_proto (method, TREE_VEC_ELT (existing_entry, i), 1))
|
||||
return;
|
||||
|
||||
/* Else, create a new, bigger vector and add the new method
|
||||
at the end of it. This is inefficient but extremely
|
||||
rare; in any sane program most methods have a single
|
||||
prototype, and very few, if any, will have more than
|
||||
2! */
|
||||
new_entry = make_tree_vec (TREE_VEC_LENGTH (existing_entry) + 1);
|
||||
|
||||
/* Copy the methods from the existing vector. */
|
||||
for (i = 0; i < TREE_VEC_LENGTH (existing_entry); i++)
|
||||
TREE_VEC_ELT (new_entry, i) = TREE_VEC_ELT (existing_entry, i);
|
||||
|
||||
/* Add the new method at the end. */
|
||||
TREE_VEC_ELT (new_entry, i) = method;
|
||||
}
|
||||
|
||||
/* Store the new vector in the map. */
|
||||
objc_map_put (map, method_name, new_entry);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* WARNING!!!! hash_enter is called with a method, and will peek
|
||||
inside to find its selector! But hash_lookup is given a selector
|
||||
directly, and looks for the selector that's inside the found
|
||||
entry's key (method) for comparison. */
|
||||
|
||||
static void
|
||||
hash_enter (hash *hashlist, tree method)
|
||||
{
|
||||
hash obj;
|
||||
int slot = hash_func (METHOD_SEL_NAME (method)) % SIZEHASHTABLE;
|
||||
|
||||
obj = ggc_alloc_hashed_entry ();
|
||||
obj->list = 0;
|
||||
obj->next = hashlist[slot];
|
||||
obj->key = method;
|
||||
|
||||
hashlist[slot] = obj; /* append to front */
|
||||
}
|
||||
|
||||
static hash
|
||||
hash_lookup (hash *hashlist, tree sel_name)
|
||||
{
|
||||
hash target;
|
||||
|
||||
target = hashlist[hash_func (sel_name) % SIZEHASHTABLE];
|
||||
|
||||
while (target)
|
||||
{
|
||||
if (sel_name == METHOD_SEL_NAME (target->key))
|
||||
return target;
|
||||
|
||||
target = target->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
hash_add_attr (hash entry, tree value)
|
||||
{
|
||||
attr obj;
|
||||
|
||||
obj = ggc_alloc_hashed_attribute ();
|
||||
obj->next = entry->list;
|
||||
obj->value = value;
|
||||
|
||||
entry->list = obj; /* append to front */
|
||||
}
|
||||
|
||||
static tree
|
||||
lookup_method (tree mchain, tree method)
|
||||
|
|
@ -5988,31 +5951,6 @@ lookup_method_static (tree interface, tree ident, int flags)
|
|||
}
|
||||
}
|
||||
|
||||
/* Add the method to the hash list if it doesn't contain an identical
|
||||
method already. */
|
||||
|
||||
static void
|
||||
add_method_to_hash_list (hash *hash_list, tree method)
|
||||
{
|
||||
hash hsh;
|
||||
|
||||
if (!(hsh = hash_lookup (hash_list, METHOD_SEL_NAME (method))))
|
||||
{
|
||||
/* Install on a global chain. */
|
||||
hash_enter (hash_list, method);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check types against those; if different, add to a list. */
|
||||
attr loop;
|
||||
int already_there = comp_proto_with_proto (method, hsh->key, 1);
|
||||
for (loop = hsh->list; !already_there && loop; loop = loop->next)
|
||||
already_there |= comp_proto_with_proto (method, loop->value, 1);
|
||||
if (!already_there)
|
||||
hash_add_attr (hsh, method);
|
||||
}
|
||||
}
|
||||
|
||||
static tree
|
||||
objc_add_method (tree klass, tree method, int is_class, bool is_optional)
|
||||
{
|
||||
|
|
@ -6135,10 +6073,10 @@ objc_add_method (tree klass, tree method, int is_class, bool is_optional)
|
|||
}
|
||||
|
||||
if (is_class)
|
||||
add_method_to_hash_list (cls_method_hash_list, method);
|
||||
insert_method_into_method_map (true, method);
|
||||
else
|
||||
{
|
||||
add_method_to_hash_list (nst_method_hash_list, method);
|
||||
insert_method_into_method_map (false, method);
|
||||
|
||||
/* Instance methods in root classes (and categories thereof)
|
||||
may act as class methods as a last resort. We also add
|
||||
|
|
@ -6151,37 +6089,12 @@ objc_add_method (tree klass, tree method, int is_class, bool is_optional)
|
|||
|
||||
if (TREE_CODE (klass) == PROTOCOL_INTERFACE_TYPE
|
||||
|| !CLASS_SUPER_NAME (klass))
|
||||
add_method_to_hash_list (cls_method_hash_list, method);
|
||||
insert_method_into_method_map (true, method);
|
||||
}
|
||||
|
||||
return method;
|
||||
}
|
||||
|
||||
static tree
|
||||
add_class (tree class_name, tree name)
|
||||
{
|
||||
struct interface_tuple **slot;
|
||||
|
||||
/* Put interfaces on list in reverse order. */
|
||||
TREE_CHAIN (class_name) = interface_chain;
|
||||
interface_chain = class_name;
|
||||
|
||||
if (interface_htab == NULL)
|
||||
interface_htab = htab_create_ggc (31, hash_interface, eq_interface, NULL);
|
||||
slot = (struct interface_tuple **)
|
||||
htab_find_slot_with_hash (interface_htab, name,
|
||||
IDENTIFIER_HASH_VALUE (name),
|
||||
INSERT);
|
||||
if (!*slot)
|
||||
{
|
||||
*slot = ggc_alloc_cleared_interface_tuple ();
|
||||
(*slot)->id = name;
|
||||
}
|
||||
(*slot)->class_name = class_name;
|
||||
|
||||
return interface_chain;
|
||||
}
|
||||
|
||||
static void
|
||||
add_category (tree klass, tree category)
|
||||
{
|
||||
|
|
@ -6951,8 +6864,8 @@ start_class (enum tree_code code, tree class_name, tree super_name,
|
|||
{
|
||||
warning (0, "cannot find interface declaration for %qE",
|
||||
class_name);
|
||||
add_class (implementation_template = objc_implementation_context,
|
||||
class_name);
|
||||
add_interface (implementation_template = objc_implementation_context,
|
||||
class_name);
|
||||
}
|
||||
|
||||
/* If a super class has been specified in the implementation,
|
||||
|
|
@ -6985,7 +6898,7 @@ start_class (enum tree_code code, tree class_name, tree super_name,
|
|||
warning (0, "duplicate interface declaration for class %qE", class_name);
|
||||
#endif
|
||||
else
|
||||
add_class (klass, class_name);
|
||||
add_interface (klass, class_name);
|
||||
|
||||
if (protocol_list)
|
||||
CLASS_PROTOCOL_LIST (klass)
|
||||
|
|
|
|||
|
|
@ -252,12 +252,6 @@ struct GTY(()) hashed_entry {
|
|||
|
||||
#define SIZEHASHTABLE 257
|
||||
|
||||
extern GTY ((length ("SIZEHASHTABLE"))) hash *nst_method_hash_list;
|
||||
extern GTY ((length ("SIZEHASHTABLE"))) hash *cls_method_hash_list;
|
||||
|
||||
extern GTY ((length ("SIZEHASHTABLE"))) hash *cls_name_hash_list;
|
||||
extern GTY ((length ("SIZEHASHTABLE"))) hash *als_name_hash_list;
|
||||
|
||||
/* An array of all the local variables in the current function that
|
||||
need to be marked as volatile. */
|
||||
extern GTY(()) VEC(tree,gc) *local_variables_to_volatilize;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,161 @@
|
|||
/* objc-map.c -- Implementation of map data structures for ObjC compiler
|
||||
Copyright 2011 Free Software Foundation, Inc.
|
||||
Written by Nicola Pero <nicola.pero@meta-innovation.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser Public License as published by the
|
||||
Free Software Foundation; either version 3, 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 Lesser Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, 51 Franklin Street - Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tree.h"
|
||||
#include "ggc.h"
|
||||
#include "objc-map.h"
|
||||
|
||||
#define OUT_OF_MEMORY { fprintf (stderr, "Out of memory\n"); abort (); }
|
||||
|
||||
static
|
||||
size_t
|
||||
ATTRIBUTE_PURE
|
||||
next_power_of_two (size_t x)
|
||||
{
|
||||
size_t result = 1;
|
||||
|
||||
if (x < 2)
|
||||
return 2;
|
||||
|
||||
/* Avoid the long calculation if x is already a power of two. Since
|
||||
we internally always increase/shrink tables by powers of 2, the
|
||||
calculation should only be done once, when the table is first
|
||||
set up. */
|
||||
if ((x & (x - 1)) == 0)
|
||||
return x;
|
||||
|
||||
/* Calculate log_2 by counting how many times we can divide by 2
|
||||
before reaching 0. */
|
||||
while (x > 0)
|
||||
{
|
||||
x = x >> 1;
|
||||
result = result << 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
objc_map_t
|
||||
objc_map_alloc_ggc (size_t initial_capacity)
|
||||
{
|
||||
objc_map_t map = (objc_map_t) ggc_internal_cleared_vec_alloc_stat (1, sizeof (struct objc_map_private));
|
||||
if (map == NULL)
|
||||
OUT_OF_MEMORY;
|
||||
|
||||
initial_capacity = next_power_of_two (initial_capacity);
|
||||
|
||||
map->number_of_slots = initial_capacity;
|
||||
map->mask = initial_capacity - 1;
|
||||
map->maximum_load_factor = 70;
|
||||
map->max_number_of_non_empty_slots = (initial_capacity * map->maximum_load_factor) / 100;
|
||||
|
||||
map->slots = (tree *)ggc_internal_cleared_vec_alloc_stat (initial_capacity, sizeof (tree));
|
||||
map->values = (tree *)ggc_internal_cleared_vec_alloc_stat (initial_capacity, sizeof (tree));
|
||||
|
||||
if (map->slots == NULL)
|
||||
OUT_OF_MEMORY;
|
||||
|
||||
if (map->values == NULL)
|
||||
OUT_OF_MEMORY;
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
void
|
||||
objc_map_set_maximum_load_factor (objc_map_t map, int number_between_zero_and_one_hundred)
|
||||
{
|
||||
if (map->number_of_non_empty_slots != 0)
|
||||
return;
|
||||
|
||||
map->maximum_load_factor = number_between_zero_and_one_hundred;
|
||||
map->max_number_of_non_empty_slots = (map->number_of_slots * number_between_zero_and_one_hundred) / 100;
|
||||
}
|
||||
|
||||
int
|
||||
objc_map_maximum_load_factor (objc_map_t map)
|
||||
{
|
||||
return map->maximum_load_factor;
|
||||
}
|
||||
|
||||
static void
|
||||
objc_map_private_resize (objc_map_t map, size_t new_number_of_slots)
|
||||
{
|
||||
tree *old_slots = map->slots;
|
||||
tree *old_values = map->values;
|
||||
size_t i, old_number_of_slots = map->number_of_slots;
|
||||
|
||||
if (new_number_of_slots < (map->number_of_non_empty_slots))
|
||||
new_number_of_slots = 2 * map->number_of_non_empty_slots;
|
||||
|
||||
new_number_of_slots = next_power_of_two (new_number_of_slots);
|
||||
|
||||
map->number_of_slots = new_number_of_slots;
|
||||
map->mask = map->number_of_slots - 1;
|
||||
map->max_number_of_non_empty_slots = (map->number_of_slots * map->maximum_load_factor) / 100;
|
||||
|
||||
|
||||
map->slots = (tree *)ggc_internal_cleared_vec_alloc_stat (map->number_of_slots, sizeof (tree));
|
||||
map->values = (tree *)ggc_internal_cleared_vec_alloc_stat (map->number_of_slots, sizeof (tree));
|
||||
|
||||
if (map->slots == NULL)
|
||||
OUT_OF_MEMORY;
|
||||
|
||||
if (map->values == NULL)
|
||||
OUT_OF_MEMORY;
|
||||
|
||||
for (i = 0; i < old_number_of_slots; i++)
|
||||
if (old_slots[i] != OBJC_MAP_PRIVATE_EMPTY_SLOT)
|
||||
{
|
||||
size_t k = IDENTIFIER_HASH_VALUE (old_slots[i]) & map->mask;
|
||||
|
||||
if (map->slots[k] == OBJC_MAP_PRIVATE_EMPTY_SLOT)
|
||||
{
|
||||
map->slots[k] = old_slots[i];
|
||||
map->values[k] = old_values[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t j = 1;
|
||||
while (1)
|
||||
{
|
||||
k = (k + j) & map->mask;
|
||||
if (map->slots[k] == OBJC_MAP_PRIVATE_EMPTY_SLOT)
|
||||
{
|
||||
map->slots[k] = old_slots[i];
|
||||
map->values[k] = old_values[i];
|
||||
break;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ggc_free (old_slots);
|
||||
ggc_free (old_values);
|
||||
}
|
||||
|
||||
void
|
||||
objc_map_private_grow (struct objc_map_private *map)
|
||||
{
|
||||
objc_map_private_resize (map, map->number_of_slots * 2);
|
||||
}
|
||||
|
||||
#include "gt-objc-objc-map.h"
|
||||
|
|
@ -0,0 +1,309 @@
|
|||
/* objc-map.h -- Implementation of map data structures for ObjC compiler
|
||||
Copyright 2011 Free Software Foundation, Inc.
|
||||
Written by Nicola Pero <nicola.pero@meta-innovation.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser Public License as published by the
|
||||
Free Software Foundation; either version 3, 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 Lesser Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, 51 Franklin Street - Fifth Floor,
|
||||
Boston, MA 02110-1301, USA. */
|
||||
|
||||
#ifndef OBJC_MAP_H
|
||||
#define OBJC_MAP_H
|
||||
|
||||
/* A map is a data structure that maps a key to a value. In this file
|
||||
we currently have maps that can map a GCC identifier (a tree) to
|
||||
some other GCC tree. This is what the ObjC frontend mostly needs:
|
||||
being able to look up an identifier into an ObjC data structure. A
|
||||
typical usage is mapping ObjC class names (as identifiers) to a
|
||||
tree representing the class.
|
||||
|
||||
This implementation is fast. :-) */
|
||||
|
||||
/**
|
||||
** Private definitions.
|
||||
**/
|
||||
|
||||
/* We include private declaration and definitions that are required to
|
||||
provide the implementation of inline functions. You should ignore
|
||||
these definitions (and the implementation of the inline functions)
|
||||
as they are not part of the public API and may change. */
|
||||
typedef unsigned int objc_map_private_hash_t;
|
||||
|
||||
/* This is used as sentinel. */
|
||||
#define OBJC_MAP_PRIVATE_EMPTY_SLOT (tree)0
|
||||
|
||||
struct GTY(()) objc_map_private {
|
||||
/* Total number of slots. This is the maximum number of elements
|
||||
that can be currently stored in the map before resizing. This is
|
||||
the number of slots in the C array. Important: this is
|
||||
guaranteed to be a power of 2. When we create (or resize) the
|
||||
map, we round up the size to the next power of 2. This allows us
|
||||
to convert a hash to a position in the hashtable by simply doing
|
||||
"position = hash & mask", where mask is number_of_slots - 1
|
||||
instead of using a modulo (which requires a division). */
|
||||
size_t number_of_slots;
|
||||
|
||||
/* This is number_of_slots - 1, precomputed. */
|
||||
size_t mask;
|
||||
|
||||
/* Number of slots that are not empty (ie, that are active). We
|
||||
keep counts using this variable which can easily be checked
|
||||
against max_number_of_non_empty_slots. */
|
||||
size_t number_of_non_empty_slots;
|
||||
|
||||
/* This is the load factor limit. When the number of non empty
|
||||
slots equals this number, we need to resize the array. This is
|
||||
calculated once, when the slots are resized, and then kept cached
|
||||
so it can be compared quickly when elements are added. */
|
||||
size_t max_number_of_non_empty_slots;
|
||||
|
||||
/* The maximum load factor. */
|
||||
int maximum_load_factor;
|
||||
|
||||
/* These are the keys. */
|
||||
tree * GTY ((length ("%h.number_of_slots"))) slots;
|
||||
|
||||
/* These are the values. values[i] is the the value corresponding
|
||||
to slots[i]. */
|
||||
tree * GTY ((length ("%h.number_of_slots"))) values;
|
||||
};
|
||||
|
||||
/* Private functions used to resize the map. They may be called by
|
||||
the inline functions when adding elements. */
|
||||
extern void
|
||||
objc_map_private_grow (struct objc_map_private *map);
|
||||
|
||||
|
||||
/**
|
||||
** The definition of a map.
|
||||
**/
|
||||
typedef struct objc_map_private *objc_map_t;
|
||||
|
||||
|
||||
/**
|
||||
** Creating a map.
|
||||
**/
|
||||
|
||||
/* objc_map_alloc_ggc() creates a new map which is under GGC. The initial
|
||||
capacity must be specified as an argument; this is used to size the map
|
||||
when it is created. */
|
||||
objc_map_t objc_map_alloc_ggc (size_t initial_capacity);
|
||||
|
||||
/**
|
||||
** Performance tuning.
|
||||
**/
|
||||
|
||||
/* Set a maximum load factor for the data structure. This is the main
|
||||
tuning parameter to improve performance (at the expense of
|
||||
memory). */
|
||||
void objc_map_set_maximum_load_factor (objc_map_t map, int number_between_zero_and_one_hundred);
|
||||
|
||||
/* Read the maximum load factor. */
|
||||
int objc_map_maximum_load_factor (objc_map_t map);
|
||||
|
||||
|
||||
/**
|
||||
** Getting the value corresponding to a key.
|
||||
**/
|
||||
|
||||
/* This is the value returned by objc_map_get() when the value
|
||||
corresponding to a key is not found. */
|
||||
#define OBJC_MAP_NOT_FOUND (tree)1
|
||||
|
||||
/* objc_map_get() returns the value associated with a certain key,
|
||||
or OBJC_MAP_NOT_FOUND if there is no value associated with that key.
|
||||
Note that you can also use it to simply check if the map contains a
|
||||
pair with a certain key; just compare the result of calling
|
||||
objc_map_get() to OBJC_MAP_NOT_FOUND.
|
||||
|
||||
It is essential to always check the results of the call to make
|
||||
sure it is not OBJC_MAP_NOT_FOUND.
|
||||
|
||||
NULL is a valid value, so a key can be inserted into a map with
|
||||
value NULL, and objc_map_get() will return NULL in that case.
|
||||
So a result of NULL means that they key *was* found, and the value
|
||||
associated with it was NULL. */
|
||||
static inline tree
|
||||
objc_map_get (objc_map_t map, /* struct tree_identifier * */tree key)
|
||||
{
|
||||
/* The inline implementation is private and may change without notice. */
|
||||
objc_map_private_hash_t hash = IDENTIFIER_HASH_VALUE (key);
|
||||
size_t i = hash & map->mask;
|
||||
size_t j = 1;
|
||||
|
||||
if (map->slots[i] == OBJC_MAP_PRIVATE_EMPTY_SLOT)
|
||||
return OBJC_MAP_NOT_FOUND;
|
||||
|
||||
if (map->slots[i] == key)
|
||||
return map->values[i];
|
||||
|
||||
while (1)
|
||||
{
|
||||
i = (i + j) & map->mask;
|
||||
|
||||
if (map->slots[i] == OBJC_MAP_PRIVATE_EMPTY_SLOT)
|
||||
return OBJC_MAP_NOT_FOUND;
|
||||
|
||||
if (map->slots[i] == key)
|
||||
return map->values[i];
|
||||
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
/* objc_map_put() puts a key/value pair into the map. If the map does
|
||||
not contain the key, it is added to it with the specified value.
|
||||
If the map already contains the key, the previous value is replaced
|
||||
with the new one.
|
||||
|
||||
You can use any identifier as key, with the exception of NULL.
|
||||
|
||||
You can use any tree as value, including NULL. */
|
||||
static inline
|
||||
void objc_map_put (objc_map_t map, /*struct tree_identifier * */tree key, tree value)
|
||||
{
|
||||
/* The inline implementation is private and may change without notice. */
|
||||
objc_map_private_hash_t hash = IDENTIFIER_HASH_VALUE (key);
|
||||
size_t i, j = 0;
|
||||
|
||||
if (map->number_of_non_empty_slots == map->max_number_of_non_empty_slots)
|
||||
objc_map_private_grow (map);
|
||||
|
||||
i = hash & map->mask;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (map->slots[i] == OBJC_MAP_PRIVATE_EMPTY_SLOT)
|
||||
{
|
||||
map->number_of_non_empty_slots++;
|
||||
map->slots[i] = key;
|
||||
map->values[i] = value;
|
||||
return;
|
||||
}
|
||||
if (map->slots[i] == key)
|
||||
{
|
||||
map->values[i] = value;
|
||||
return;
|
||||
}
|
||||
|
||||
j++;
|
||||
i = (i + j) & map->mask;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** Iterating over a map using an iterator.
|
||||
**/
|
||||
|
||||
/* When using iterators you can iterate directly on the elements in
|
||||
the map, and take an action over each one.
|
||||
|
||||
Here is how you iterate over a hmap_pointer using iterators:
|
||||
|
||||
objc_map_iterator_t i;
|
||||
|
||||
objc_map_iterator_initialize (map, &i);
|
||||
|
||||
while (objc_map_iterator_move_to_next (map, &i))
|
||||
{
|
||||
tree p = objc_map_iterator_current_key (map, i);
|
||||
tree q = objc_map_iterator_current_value (map, i);
|
||||
|
||||
... do something with p and q ...
|
||||
}
|
||||
|
||||
You'll notice that the functions that modify the iterator (to
|
||||
initialize it, or move it to the next element) take a pointer to it
|
||||
as argument (as in "&i"), while the functions that only read its
|
||||
state (to read the current key/value, or remove the current
|
||||
key/value from the map) take it as a direct argument (as in "i").
|
||||
|
||||
Note that all the objc_map_iterator_*() functions are inline and if
|
||||
you follow the pattern above, the compiler should be able to inline
|
||||
everything into a very efficient loop, roughly equivalent to
|
||||
hand-writing a C loop that iterates directly onto the hmap_pointer
|
||||
internal data structures. */
|
||||
|
||||
/* A objc_map_iterator_t variable encapsulates the state of an
|
||||
iteration. The fact that this is actually a size_t (pointing to
|
||||
the index of the slot that we return next) is an internal, private
|
||||
detail of the implementation and may change without notice. */
|
||||
typedef size_t objc_map_iterator_t;
|
||||
|
||||
/* Initialize an iterator to iterate over the specified objc_map. You
|
||||
must use this before starting the iteration, to get a working
|
||||
iterator. */
|
||||
static inline
|
||||
void
|
||||
objc_map_iterator_initialize (objc_map_t map ATTRIBUTE_UNUSED, objc_map_iterator_t *i)
|
||||
{
|
||||
/* The inline implementation is private and may change without notice. */
|
||||
/* This is trivial, but the same API would work to initialize more
|
||||
complicated iterators. */
|
||||
*i = 0;
|
||||
}
|
||||
|
||||
#define OBJC_MAP_FAILURE 0
|
||||
#define OBJC_MAP_SUCCESS 1
|
||||
|
||||
/* Move the iterator to the next key/value pair, and return
|
||||
OBJC_MAP_SUCCESS if there is such a key/value pair, and
|
||||
OBJC_MAP_FAILURE if there are no more ones. The iterator must have
|
||||
been initialized using objc_map_iterator_initialize(). Note that
|
||||
because this function is modifying the iterator, you need to pass a
|
||||
pointer to it. */
|
||||
static inline
|
||||
int
|
||||
objc_map_iterator_move_to_next (objc_map_t map, objc_map_iterator_t *i)
|
||||
{
|
||||
/* The inline implementation is private and may change without notice. */
|
||||
while (1)
|
||||
{
|
||||
void *slot;
|
||||
if (*i == map->number_of_slots)
|
||||
return OBJC_MAP_FAILURE;
|
||||
|
||||
slot = map->slots[*i];
|
||||
*i = *i + 1;
|
||||
if (slot != OBJC_MAP_PRIVATE_EMPTY_SLOT)
|
||||
return OBJC_MAP_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the current key. You can only call it after you have called
|
||||
objc_map_iterator_move_to_next() at least once (to move to the
|
||||
first element), and only if the last call returned
|
||||
OBJC_MAP_SUCCESS. The behaviour is otherwise undefined, probably a
|
||||
segmentation fault. */
|
||||
static inline
|
||||
tree
|
||||
objc_map_iterator_current_key (objc_map_t map, objc_map_iterator_t i)
|
||||
{
|
||||
/* The inline implementation is private and may change without notice. */
|
||||
return map->slots[i - 1];
|
||||
}
|
||||
|
||||
/* Return the current value. You can only call it after you have
|
||||
called objc_map_iterator_move_to_next() at least once (to move to
|
||||
the first element), and only if the last call returned
|
||||
OBJC_MAP_SUCCESS. The behaviour is otherwise undefined, probably a
|
||||
segmentation fault. */
|
||||
static inline
|
||||
tree
|
||||
objc_map_iterator_current_value (objc_map_t map, objc_map_iterator_t i)
|
||||
{
|
||||
/* The inline implementation is private and may change without notice. */
|
||||
return map->values[i - 1];
|
||||
}
|
||||
|
||||
#endif /* OBJC_MAP_H */
|
||||
|
|
@ -231,6 +231,7 @@ static tree begin_catch (struct objc_try_context **, tree, tree, tree, bool);
|
|||
static void finish_catch (struct objc_try_context **, tree);
|
||||
static tree finish_try_stmt (struct objc_try_context **);
|
||||
|
||||
/* TODO: Use an objc-map. */
|
||||
static GTY ((length ("SIZEHASHTABLE"))) hash *extern_names;
|
||||
|
||||
bool
|
||||
|
|
|
|||
|
|
@ -1,3 +1,10 @@
|
|||
2011-10-14 Nicola Pero <nicola.pero@meta-innovation.com>
|
||||
|
||||
* Make-lang.in (OBJCXX_OBJS): Added objc-map.o.
|
||||
(objcp/objc-map.o): New rule.
|
||||
(objcp/objcp-act.o): Depend on objc/objc-map.h.
|
||||
* config-lang.in (gtfiles): Added objc-map.h.
|
||||
|
||||
2011-07-11 Nicola Pero <nicola.pero@meta-innovation.com>
|
||||
|
||||
* Make-lang.in (objcp/objc-runtime-shared-support.o): Do not
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ OBJCXX_OBJS = objcp/objcp-act.o objcp/objcp-lang.o objcp/objcp-decl.o \
|
|||
objcp/objc-next-runtime-abi-01.o \
|
||||
objcp/objc-next-runtime-abi-02.o \
|
||||
objcp/objc-encoding.o \
|
||||
objcp/objc-map.o \
|
||||
$(CXX_AND_OBJCXX_OBJS)
|
||||
|
||||
obj-c++_OBJS = $(OBJCXX_OBJS) cc1objplus-checksum.o
|
||||
|
|
@ -149,6 +150,7 @@ objcp/objcp-act.o : objc/objc-act.c \
|
|||
$(RTL_H) $(EXPR_H) $(TARGET_H) \
|
||||
objcp/objcp-decl.h \
|
||||
objc/objc-encoding.h \
|
||||
objc/objc-map.h \
|
||||
objc/objc-runtime-hooks.h \
|
||||
objc/objc-runtime-shared-support.h \
|
||||
objcp/objcp-decl.h
|
||||
|
|
@ -165,6 +167,14 @@ objcp/objc-encoding.o : objc/objc-encoding.c \
|
|||
$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< \
|
||||
$(OUTPUT_OPTION)
|
||||
|
||||
objcp/objc-map.o : objc/objc-map.c \
|
||||
$(START_HDRS) \
|
||||
$(GGC_H) $(DIAGNOSTIC_CORE_H) $(FLAGS_H) input.h \
|
||||
$(OBSTACK_H) \
|
||||
objc/objc-map.h
|
||||
$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< \
|
||||
$(OUTPUT_OPTION)
|
||||
|
||||
po-generated:
|
||||
|
||||
#
|
||||
|
|
|
|||
|
|
@ -46,5 +46,5 @@ subdir_requires="objc cp"
|
|||
# This list is separated in two parts: the first one is identical to
|
||||
# the C++ one, the second one contains our ObjC++ additions.
|
||||
gtfiles="\$(srcdir)/cp/rtti.c \$(srcdir)/cp/mangle.c \$(srcdir)/cp/name-lookup.h \$(srcdir)/cp/name-lookup.c \$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/semantics.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/parser.h \$(srcdir)/cp/parser.c \$(srcdir)/cp/method.c \$(srcdir)/cp/typeck2.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-lex.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/cp/class.c \$(srcdir)/cp/cp-objcp-common.c \
|
||||
\$(srcdir)/objc/objc-act.h \$(srcdir)/objc/objc-act.c \$(srcdir)/objc/objc-runtime-shared-support.c \$(srcdir)/objc/objc-gnu-runtime-abi-01.c \$(srcdir)/objc/objc-next-runtime-abi-01.c \$(srcdir)/objc/objc-next-runtime-abi-02.c \$(srcdir)/c-family/c-cppbuiltin.c"
|
||||
\$(srcdir)/objc/objc-map.h \$(srcdir)/objc/objc-act.h \$(srcdir)/objc/objc-act.c \$(srcdir)/objc/objc-runtime-shared-support.c \$(srcdir)/objc/objc-gnu-runtime-abi-01.c \$(srcdir)/objc/objc-next-runtime-abi-01.c \$(srcdir)/objc/objc-next-runtime-abi-02.c \$(srcdir)/c-family/c-cppbuiltin.c"
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue