summaryrefslogtreecommitdiff
path: root/libobjc
diff options
context:
space:
mode:
authorbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2011-01-03 12:17:59 +0000
committerbstarynk <bstarynk@138bc75d-0d04-0410-961f-82ee72b054a4>2011-01-03 12:17:59 +0000
commit73556f5f6c5d835df3baa9979de74da7bd85cd05 (patch)
treeac76e75c45976914468f05d9d01c6dab44ff831c /libobjc
parent009b254c18c50184aadbc41673222104cec47838 (diff)
downloadgcc-73556f5f6c5d835df3baa9979de74da7bd85cd05.tar.gz
2011-01-03 Basile Starynkevitch <basile@starynkevitch.net>
MELT branch merged with trunk rev 168414 git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/melt-branch@168419 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libobjc')
-rw-r--r--libobjc/ChangeLog169
-rw-r--r--libobjc/Makefile.in6
-rw-r--r--libobjc/class.c28
-rw-r--r--libobjc/hash.c285
-rw-r--r--libobjc/init.c366
-rw-r--r--libobjc/ivars.c3
-rw-r--r--libobjc/linking.m1
-rw-r--r--libobjc/objc-private/accessors.h8
-rw-r--r--libobjc/objc-private/common.h19
-rw-r--r--libobjc/objc-private/hash.h10
-rw-r--r--libobjc/objc-private/module-abi-8.h10
-rw-r--r--libobjc/objc-private/objc-list.h61
-rw-r--r--libobjc/objc-private/objc-sync.h8
-rw-r--r--libobjc/objc-private/protocols.h8
-rw-r--r--libobjc/objc-private/runtime.h36
-rw-r--r--libobjc/objc-private/sarray.h154
-rw-r--r--libobjc/objc-private/selector.h13
-rw-r--r--libobjc/objc/runtime.h75
-rw-r--r--libobjc/selector.c244
-rw-r--r--libobjc/sendmsg.c59
20 files changed, 1017 insertions, 546 deletions
diff --git a/libobjc/ChangeLog b/libobjc/ChangeLog
index 55f35dc3989..bb00682b80f 100644
--- a/libobjc/ChangeLog
+++ b/libobjc/ChangeLog
@@ -1,8 +1,175 @@
+2010-12-26 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * init.c (create_tree_of_subclasses_inherited_from): Use
+ class_superclass_of_class instead of assuming a class is
+ unresolved when it could be resolved. Tidied up assignment and
+ check.
+ (__objc_tree_insert_class): Enhanced DEBUG_PRINTF.
+ (objc_tree_insert_class): Tidied up loop; return immediately upon
+ inserting a class.
+ (__objc_exec_class): Do not set __objc_class_tree_list.
+
+2010-12-24 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * selector.c (sel_getTypedSelector): Return NULL if given a NULL
+ argument.
+ (sel_registerTypedName): Same.
+ (sel_registerName): Same.
+ * objc/runtime.h: Updated documentation.
+
+2010-12-24 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * objc/runtime.h (class_addIvar): Updated documentation. The
+ alignment is actually the log_2 of the alignment in bytes.
+ * ivars.c (class_addIvar): Corresponding change to the
+ implementation.
+
+2010-12-24 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * objc/runtime.h (sel_getType): Renamed to sel_getTypeEncoding to
+ be consistent with method_getTypeEncoding and
+ ivar_getTypeEncoding.
+ (sel_copyTypedSelectorList, sel_getTypedSelector): New.
+ * selector.c (sel_getType): Renamed to sel_getTypeEncoding.
+ (sel_copyTypedSelectorList, sel_getTypedSelector): New.
+ (sel_get_type): Updated call to sel_getType.
+
+2010-12-24 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * objc/runtime.h (class_conformsToProtocol,
+ class_copyProtocolList): Updated documentation.
+
+2010-12-23 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * init.c (create_tree_of_subclasses_inherited_from): Updated
+ DEBUG_PRINTF messages.
+ (__objc_tree_insert_class): Same.
+ (__objc_send_load_using_method_list): Same.
+ (__objc_send_load): Same.
+ (__objc_exec_class): Same. In particular, do not print the module
+ name since it is no longer used.
+ * sendmsg.c (__objc_send_initialize): Added DEBUG_PRINTFs for
+ tracking +initialize calls.
+ (__objc_update_dispatch_table_for_class): Added DEBUG_PRINTFs for
+ tracking updates of dispatch tables.
+ (__objc_install_dispatch_table_for_class): Same.
+
+2010-12-23 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * Makefile.in (libobjc$(libsuffix).la): Link with -Wc,-shared-libgcc.
+ (libobjc_gc$(libsuffix).la): Likewise.
+
+2010-12-23 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * sendmsg.c (class_addMethod): Return NO if the method already
+ exists in the class.
+
+2010-12-22 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * init.c (duplicate_classes): New.
+ (__objc_exec_class): Initialize duplicate_classes.
+ (__objc_create_classes_tree): Ignore classes in the
+ duplicate_classes table.
+ (__objc_call_load_callback): Same.
+ (__objc_init_class): If a duplicate class is found, add it to
+ duplicate_classes instead of aborting. Return YES if the class is
+ not a duplicate, and NO if it is.
+ * objc-private/runtime.h (__objc_init_class): Updated prototype.
+
+2010-12-22 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * objc-private/objc-list.h: Reindented file. No code changes.
+ * objc-private/sarray.h: Same change.
+
+2010-12-22 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * objc-private/accessors.h: Removed 'extern "C"' guards. This
+ file is never compiled with C++.
+ * objc-private/hash.h: Same change.
+ * objc-private/objc-list.h: Same change.
+ * objc-private/objc-sync.h: Same change.
+ * objc-private/protocols.h: Same change.
+ * objc-private/runtime.h: Same change.
+ * objc-private/sarray.h: Same change.
+ * objc-private/selector.h: Same change.
+
+2010-12-21 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ PR libobjc/18764
+ * class.c (__objc_add_class_to_hash): Return YES if the class was
+ added, and NO if it already existed.
+ * init.c (__objc_init_class): If __objc_add_class_to_hash returns
+ NO, then abort the program with an error message.
+ * objc-private/runtime.h (__objc_add_class_to_hash): Updated
+ declaration.
+
+2010-12-21 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * init.c (_objc_load_callback): Initialize with 0.
+ (__objc_call_callback): Renamed to __objc_call_load_callback.
+ Check _objc_load_callback only once, and if it is not set, return
+ immediately.
+ (objc_send_load): Updated call to __objc_call_callback.
+
+2010-12-21 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ PR libobjc/16110
+ * init.c (__objc_send_message_in_list): Renamed to
+ __objc_send_load_using_method_list. Do not take an 'op' argument.
+ Register the 'load' selector if needed.
+ (__objc_send_load): Do not register the 'load' selector. Updated
+ call to __objc_send_message_in_list.
+ (__objc_create_classes_tree): Add the class of any claimed
+ category that was loaded in the module to the list of classes for
+ which we try to execute +load.
+
+2010-12-21 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * objc-private/common.h: When DEBUG is defined, include <stdio.h>.
+ Updated comments.
+ * init.c (__objc_tree_insert_class): Use %p, not %x, when printing
+ a pointer using DEBUG_PRINTF.
+
+2010-12-21 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ PR libobjc/45953
+ * selector.c (__sel_register_typed_name): When registering a new
+ selector with the same name as an existing one, reuse the existing
+ name string. Also updated types, casts and comments in the whole
+ function.
+
+2010-12-21 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * objc-private/module-abi-8.h (struct objc_symtab): Declare 'refs'
+ to be 'struct objc_selector *' and not 'SEL'.
+ * init.c (__objc_exec_class): Call
+ __objc_register_selectors_from_module instead of iterating over
+ each selector and calling __sel_register_typed_name for each.
+ * objc-private/selector.h: Declare
+ __objc_register_selectors_from_module instead of
+ __sel_register_typed_name.
+ * selector.c (__objc_register_selectors_from_module): New.
+ (__sel_register_typed_name): Made static.
+
+2010-12-21 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * linking.m: Do not include objc/NXConstStr.h.
+
+2010-12-21 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * objc-private/runtime.h (DEBUG_PRINTF): Moved from here ...
+ * objc-private/common.h (DEBUG_PRINTF): To here.
+ * hash.c: Do not include objc-private/runtime.h and objc/thr.h.
+
+2010-12-21 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * hash.c: Tidied up comments and indentation. No code changes.
+
2010-12-19 Nicola Pero <nicola.pero@meta-innovation.com>
PR libobjc/47012
* accessors.m (objc_getProperty): If not atomic, do not
- retain/autorelease the returned value. (Problem reported by
+ retain/autorelease the returned value.
2010-12-19 Nicola Pero <nicola.pero@meta-innovation.com>
diff --git a/libobjc/Makefile.in b/libobjc/Makefile.in
index c519542e072..b33c989e6d2 100644
--- a/libobjc/Makefile.in
+++ b/libobjc/Makefile.in
@@ -1,6 +1,6 @@
# Makefile for GNU Objective C runtime library.
# Copyright 1993, 1995, 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004,
-# 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+# 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
#This file is part of GCC.
@@ -325,13 +325,13 @@ LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS))
libobjc$(libsuffix).la: $(OBJS)
$(LIBTOOL_LINK) $(CC) -o $@ $(OBJS) \
- -rpath $(toolexeclibdir) \
+ -Wc,-shared-libgcc -rpath $(toolexeclibdir) \
-version-info $(LIBOBJC_VERSION) $(extra_ldflags_libobjc) \
$(LTLDFLAGS)
libobjc_gc$(libsuffix).la: $(OBJS_GC)
$(LIBTOOL_LINK) $(CC) -o $@ $(OBJS_GC) $(OBJC_BOEHM_GC_LIBS) \
- -rpath $(toolexeclibdir) \
+ -Wc,-shared-libgcc -rpath $(toolexeclibdir) \
-version-info $(LIBOBJC_GC_VERSION) $(extra_ldflags_libobjc) \
$(LTLDFLAGS)
diff --git a/libobjc/class.c b/libobjc/class.c
index cf8e4c42728..b9e8730beb2 100644
--- a/libobjc/class.c
+++ b/libobjc/class.c
@@ -446,11 +446,12 @@ __objc_init_class_tables (void)
}
/* This function adds a class to the class hash table, and assigns the
- class a number, unless it's already known. */
-void
+ class a number, unless it's already known. Return 'YES' if the
+ class was added. Return 'NO' if the class was already known. */
+BOOL
__objc_add_class_to_hash (Class class)
{
- Class h_class;
+ Class existing_class;
objc_mutex_lock (__objc_runtime_mutex);
@@ -461,21 +462,28 @@ __objc_add_class_to_hash (Class class)
assert (CLS_ISCLASS (class));
/* Check to see if the class is already in the hash table. */
- h_class = class_table_get_safe (class->name);
- if (! h_class)
+ existing_class = class_table_get_safe (class->name);
+
+ if (existing_class)
+ {
+ objc_mutex_unlock (__objc_runtime_mutex);
+ return NO;
+ }
+ else
{
- /* The class isn't in the hash table. Add the class and assign a class
- number. */
+ /* The class isn't in the hash table. Add the class and assign
+ a class number. */
static unsigned int class_number = 1;
-
+
CLS_SETNUMBER (class, class_number);
CLS_SETNUMBER (class->class_pointer, class_number);
++class_number;
class_table_insert (class->name, class);
- }
- objc_mutex_unlock (__objc_runtime_mutex);
+ objc_mutex_unlock (__objc_runtime_mutex);
+ return YES;
+ }
}
Class
diff --git a/libobjc/hash.c b/libobjc/hash.c
index 3ecc54a170a..138a2504db2 100644
--- a/libobjc/hash.c
+++ b/libobjc/hash.c
@@ -23,12 +23,10 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */
#include "objc-private/common.h"
-#include <assert.h> /* For assert */
+#include <assert.h> /* For assert. */
-#include "objc/runtime.h" /* For objc_calloc */
-#include "objc/thr.h" /* Required by objc-private/runtime.h. */
+#include "objc/runtime.h" /* For objc_calloc. */
#include "objc-private/hash.h"
-#include "objc-private/runtime.h" /* for DEBUG_PRINTF */
/* These two macros determine when a hash table is full and
by how much it should be expanded respectively.
@@ -49,27 +47,27 @@ objc_hash_new (unsigned int size, hash_func_type hash_func,
assert (size);
assert (! (size & (size - 1)));
- /* Allocate the cache structure. calloc insures
- its initialization for default values. */
+ /* Allocate the cache structure. calloc insures its initialization
+ for default values. */
cache = (cache_ptr) objc_calloc (1, sizeof (struct cache));
assert (cache);
- /* Allocate the array of buckets for the cache.
- calloc initializes all of the pointers to NULL. */
+ /* Allocate the array of buckets for the cache. calloc initializes
+ all of the pointers to NULL. */
cache->node_table
= (node_ptr *) objc_calloc (size, sizeof (node_ptr));
assert (cache->node_table);
cache->size = size;
- /* This should work for all processor architectures? */
+ /* This should work for all processor architectures (?). */
cache->mask = (size - 1);
/* Store the hashing function so that codes can be computed. */
cache->hash_func = hash_func;
- /* Store the function that compares hash keys to
- determine if they are equal. */
+ /* Store the function that compares hash keys to determine if they
+ are equal. */
cache->compare_func = compare_func;
return cache;
@@ -85,19 +83,22 @@ objc_hash_delete (cache_ptr cache)
/* Purge all key/value pairs from the table. */
/* Step through the nodes one by one and remove every node WITHOUT
- using objc_hash_next. this makes objc_hash_delete much more efficient. */
- for (i = 0;i < cache->size;i++) {
- if ((node = cache->node_table[i])) {
- /* an entry in the hash table has been found, now step through the
- nodes next in the list and free them. */
- while ((next_node = node->next)) {
- objc_hash_remove (cache,node->key);
- node = next_node;
- }
-
- objc_hash_remove (cache,node->key);
+ using objc_hash_next. this makes objc_hash_delete much more
+ efficient. */
+ for (i = 0; i < cache->size; i++)
+ {
+ if ((node = cache->node_table[i]))
+ {
+ /* An entry in the hash table has been found. Now step
+ through the nodes next in the list and free them. */
+ while ((next_node = node->next))
+ {
+ objc_hash_remove (cache,node->key);
+ node = next_node;
+ }
+ objc_hash_remove (cache,node->key);
+ }
}
- }
/* Release the array of nodes and the cache itself. */
objc_free(cache->node_table);
@@ -108,10 +109,9 @@ objc_hash_delete (cache_ptr cache)
void
objc_hash_add (cache_ptr *cachep, const void *key, void *value)
{
- size_t indx = (*(*cachep)->hash_func)(*cachep, key);
+ size_t indx = (*(*cachep)->hash_func) (*cachep, key);
node_ptr node = (node_ptr) objc_calloc (1, sizeof (struct cache_node));
-
assert (node);
/* Initialize the new node. */
@@ -119,16 +119,15 @@ objc_hash_add (cache_ptr *cachep, const void *key, void *value)
node->value = value;
node->next = (*cachep)->node_table[indx];
- /* Debugging.
- Check the list for another key. */
+ /* Debugging. Check the list for another key. */
#ifdef DEBUG
- { node_ptr node1 = (*cachep)->node_table[indx];
-
- while (node1) {
-
- assert (node1->key != key);
- node1 = node1->next;
- }
+ {
+ node_ptr node1 = (*cachep)->node_table[indx];
+ while (node1)
+ {
+ assert (node1->key != key);
+ node1 = node1->next;
+ }
}
#endif
@@ -137,69 +136,72 @@ objc_hash_add (cache_ptr *cachep, const void *key, void *value)
/* Bump the number of entries in the cache. */
++(*cachep)->used;
-
- /* Check the hash table's fullness. We're going
- to expand if it is above the fullness level. */
- if (FULLNESS (*cachep)) {
-
- /* The hash table has reached its fullness level. Time to
- expand it.
-
- I'm using a slow method here but is built on other
- primitive functions thereby increasing its
- correctness. */
- node_ptr node1 = NULL;
- cache_ptr new = objc_hash_new (EXPANSION (*cachep),
- (*cachep)->hash_func,
- (*cachep)->compare_func);
-
- DEBUG_PRINTF ("Expanding cache %#x from %d to %d\n",
- (int) *cachep, (*cachep)->size, new->size);
-
- /* Copy the nodes from the first hash table to the new one. */
- while ((node1 = objc_hash_next (*cachep, node1)))
- objc_hash_add (&new, node1->key, node1->value);
-
- /* Trash the old cache. */
- objc_hash_delete (*cachep);
-
- /* Return a pointer to the new hash table. */
- *cachep = new;
- }
+
+ /* Check the hash table's fullness. We're going to expand if it is
+ above the fullness level. */
+ if (FULLNESS (*cachep))
+ {
+ /* The hash table has reached its fullness level. Time to
+ expand it.
+
+ I'm using a slow method here but is built on other primitive
+ functions thereby increasing its correctness. */
+ node_ptr node1 = NULL;
+ cache_ptr new = objc_hash_new (EXPANSION (*cachep),
+ (*cachep)->hash_func,
+ (*cachep)->compare_func);
+
+ DEBUG_PRINTF ("Expanding cache %#x from %d to %d\n",
+ (int) *cachep, (*cachep)->size, new->size);
+
+ /* Copy the nodes from the first hash table to the new one. */
+ while ((node1 = objc_hash_next (*cachep, node1)))
+ objc_hash_add (&new, node1->key, node1->value);
+
+ /* Trash the old cache. */
+ objc_hash_delete (*cachep);
+
+ /* Return a pointer to the new hash table. */
+ *cachep = new;
+ }
}
-
void
objc_hash_remove (cache_ptr cache, const void *key)
{
- size_t indx = (*cache->hash_func)(cache, key);
+ size_t indx = (*cache->hash_func) (cache, key);
node_ptr node = cache->node_table[indx];
-
- /* We assume there is an entry in the table. Error if it is not. */
+ /* We assume there is an entry in the table. Error if it is
+ not. */
assert (node);
- /* Special case. First element is the key/value pair to be removed. */
- if ((*cache->compare_func)(node->key, key)) {
- cache->node_table[indx] = node->next;
- objc_free(node);
- } else {
-
- /* Otherwise, find the hash entry. */
- node_ptr prev = node;
- BOOL removed = NO;
-
- do {
-
- if ((*cache->compare_func)(node->key, key)) {
- prev->next = node->next, removed = YES;
- objc_free(node);
- } else
- prev = node, node = node->next;
- } while (! removed && node);
- assert (removed);
- }
-
+ /* Special case. First element is the key/value pair to be
+ removed. */
+ if ((*cache->compare_func) (node->key, key))
+ {
+ cache->node_table[indx] = node->next;
+ objc_free(node);
+ }
+ else
+ {
+ /* Otherwise, find the hash entry. */
+ node_ptr prev = node;
+ BOOL removed = NO;
+ do
+ {
+ if ((*cache->compare_func) (node->key, key))
+ {
+ prev->next = node->next, removed = YES;
+ objc_free(node);
+ }
+ else
+ prev = node, node = node->next;
+ }
+ while (!removed && node);
+ assert (removed);
+ }
+
/* Decrement the number of entries in the hash table. */
--cache->used;
}
@@ -208,76 +210,85 @@ objc_hash_remove (cache_ptr cache, const void *key)
node_ptr
objc_hash_next (cache_ptr cache, node_ptr node)
{
- /* If the scan is being started then reset the last node
- visitied pointer and bucket index. */
- if (! node)
+ /* If the scan is being started then reset the last node visitied
+ pointer and bucket index. */
+ if (!node)
cache->last_bucket = 0;
-
- /* If there is a node visited last then check for another
- entry in the same bucket; Otherwise step to the next bucket. */
- if (node) {
- if (node->next)
- /* There is a node which follows the last node
- returned. Step to that node and retun it. */
- return node->next;
- else
- ++cache->last_bucket;
- }
-
- /* If the list isn't exhausted then search the buckets for
- other nodes. */
- if (cache->last_bucket < cache->size) {
- /* Scan the remainder of the buckets looking for an entry
- at the head of the list. Return the first item found. */
- while (cache->last_bucket < cache->size)
- if (cache->node_table[cache->last_bucket])
- return cache->node_table[cache->last_bucket];
+
+ /* If there is a node visited last then check for another entry in
+ the same bucket. Otherwise step to the next bucket. */
+ if (node)
+ {
+ if (node->next)
+ {
+ /* There is a node which follows the last node returned.
+ Step to that node and retun it. */
+ return node->next;
+ }
else
- ++cache->last_bucket;
+ ++cache->last_bucket;
+ }
- /* No further nodes were found in the hash table. */
- return NULL;
- } else
+ /* If the list isn't exhausted then search the buckets for other
+ nodes. */
+ if (cache->last_bucket < cache->size)
+ {
+ /* Scan the remainder of the buckets looking for an entry at
+ the head of the list. Return the first item found. */
+ while (cache->last_bucket < cache->size)
+ if (cache->node_table[cache->last_bucket])
+ return cache->node_table[cache->last_bucket];
+ else
+ ++cache->last_bucket;
+
+ /* No further nodes were found in the hash table. */
+ return NULL;
+ }
+ else
return NULL;
}
-/* Given KEY, return corresponding value for it in CACHE.
- Return NULL if the KEY is not recorded. */
-
+/* Given KEY, return corresponding value for it in CACHE. Return NULL
+ if the KEY is not recorded. */
void *
objc_hash_value_for_key (cache_ptr cache, const void *key)
{
- node_ptr node = cache->node_table[(*cache->hash_func)(cache, key)];
+ node_ptr node = cache->node_table[(*cache->hash_func) (cache, key)];
void *retval = NULL;
if (node)
- do {
- if ((*cache->compare_func)(node->key, key)) {
- retval = node->value;
- break;
- } else
- node = node->next;
- } while (! retval && node);
-
+ do
+ {
+ if ((*cache->compare_func) (node->key, key))
+ {
+ retval = node->value;
+ break;
+ }
+ else
+ node = node->next;
+ }
+ while (! retval && node);
+
return retval;
}
-/* Given KEY, return YES if it exists in the CACHE.
- Return NO if it does not */
-
+/* Given KEY, return YES if it exists in the CACHE. Return NO if it
+ does not */
BOOL
objc_hash_is_key_in_hash (cache_ptr cache, const void *key)
{
- node_ptr node = cache->node_table[(*cache->hash_func)(cache, key)];
-
+ node_ptr node = cache->node_table[(*cache->hash_func) (cache, key)];
+
if (node)
- do {
- if ((*cache->compare_func)(node->key, key))
+ do
+ {
+ if ((*cache->compare_func)(node->key, key))
return YES;
- else
- node = node->next;
- } while (node);
+ else
+ node = node->next;
+ }
+ while (node);
return NO;
}
diff --git a/libobjc/init.c b/libobjc/init.c
index f1eb83ab1d2..d4475b3b787 100644
--- a/libobjc/init.c
+++ b/libobjc/init.c
@@ -24,6 +24,10 @@ a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */
+/* Uncommented the following line to enable debug logging. Use this
+ only while debugging the runtime. */
+/* #define DEBUG 1 */
+
#include "objc-private/common.h"
#include "objc-private/error.h"
#include "objc/runtime.h"
@@ -44,8 +48,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#define OBJC_VERSION 8
#define PROTOCOL_VERSION 2
-/* This list contains all modules currently loaded into the
- runtime. */
+/* This list contains modules currently loaded into the runtime and
+ for which the +load method (and the load callback, if any) has not
+ been called yet. */
static struct objc_list *__objc_module_list = 0; /* !T:MUTEX */
/* This list contains all proto_list's not yet assigned class
@@ -55,6 +60,16 @@ static struct objc_list *unclaimed_proto_list = 0; /* !T:MUTEX */
/* List of unresolved static instances. */
static struct objc_list *uninitialized_statics = 0; /* !T:MUTEX */
+/* List of duplicated classes found while loading modules. If we find
+ a class twice, we ignore it the second time. On some platforms,
+ where the order in which modules are loaded is well defined, this
+ allows you to replace a class in a shared library by linking in a
+ new implementation which is loaded in in the right order, and which
+ overrides the existing one.
+
+ Protected by __objc_runtime_mutex. */
+static cache_ptr duplicate_classes = NULL;
+
/* Global runtime "write" mutex. Having a single mutex prevents
deadlocks, but reduces concurrency. To improve concurrency, some
groups of functions in the runtime have their own separate mutex
@@ -84,9 +99,9 @@ static void __objc_init_protocol (struct objc_protocol *protocol);
static void __objc_class_add_protocols (Class, struct objc_protocol_list *);
/* Load callback hook. */
-void (*_objc_load_callback) (Class class, struct objc_category *category); /* !T:SAFE */
+void (*_objc_load_callback) (Class class, struct objc_category *category) = 0; /* !T:SAFE */
-/* Are all categories/classes resolved? */
+/* Are all categories/classes resolved ? */
BOOL __objc_dangling_categories = NO; /* !T:UNUSED */
/* Sends +load to all classes and categories in certain
@@ -94,26 +109,37 @@ BOOL __objc_dangling_categories = NO; /* !T:UNUSED */
static void objc_send_load (void);
/* Inserts all the classes defined in module in a tree of classes that
- resembles the class hierarchy. This tree is traversed in preorder
+ resembles the class hierarchy. This tree is traversed in preorder
and the classes in its nodes receive the +load message if these
- methods were not executed before. The algorithm ensures that when
+ methods were not executed before. The algorithm ensures that when
the +load method of a class is executed all the superclasses have
been already received the +load message. */
static void __objc_create_classes_tree (struct objc_module *module);
-static void __objc_call_callback (struct objc_module *module);
+/* Calls the _objc_load_callback for each class and category in the
+ module (if _objc_load_callback is not NULL). */
+static void __objc_call_load_callback (struct objc_module *module);
/* A special version that works only before the classes are completely
installed in the runtime. */
static BOOL class_is_subclass_of_class (Class class, Class superclass);
-typedef struct objc_class_tree {
+/* This is a node in the class tree hierarchy used to send +load
+ messages. */
+typedef struct objc_class_tree
+{
+ /* The class corresponding to the node. */
Class class;
- struct objc_list *subclasses; /* `head' is pointer to an objc_class_tree */
+
+ /* This is a linked list of all the direct subclasses of this class.
+ 'head' points to a subclass node; 'tail' points to the next
+ objc_list node (whose 'head' points to another subclass node,
+ etc). */
+ struct objc_list *subclasses;
} objc_class_tree;
-/* This is a linked list of objc_class_tree trees. The head of these
- trees are root classes (their super class is Nil). These different
+/* This is a linked list of objc_class_tree trees. The head of these
+ trees are root classes (their super class is Nil). These different
trees represent different class hierarchies. */
static struct objc_list *__objc_class_tree_list = NULL;
@@ -126,7 +152,7 @@ static cache_ptr __objc_load_methods = NULL;
is really needed so that superclasses will get the message before
subclasses.
- This tree will contain classes which are being loaded (or have just
+ This tree may contain classes which are being loaded (or have just
being loaded), and whose super_class pointers have not yet been
resolved. This implies that their super_class pointers point to a
string with the name of the superclass; when the first message is
@@ -165,29 +191,30 @@ static Class class_superclass_of_class (Class class)
/* Creates a tree of classes whose topmost class is directly inherited
- from `upper' and the bottom class in this tree is
- `bottom_class'. The classes in this tree are super classes of
- `bottom_class'. `subclasses' member of each tree node point to the
- next subclass tree node. */
+ from `upper' and the bottom class in this tree is `bottom_class'.
+ If `upper' is Nil, creates a class hierarchy up to a root class.
+ The classes in this tree are super classes of `bottom_class'. The
+ `subclasses' member of each tree node point to the list of
+ subclasses for the node. */
static objc_class_tree *
create_tree_of_subclasses_inherited_from (Class bottom_class, Class upper)
{
Class superclass;
objc_class_tree *tree, *prev;
- if (bottom_class->super_class)
- superclass = objc_getClass ((char *) bottom_class->super_class);
- else
- superclass = Nil;
-
DEBUG_PRINTF ("create_tree_of_subclasses_inherited_from:");
- DEBUG_PRINTF ("bottom_class = %s, upper = %s\n",
+ DEBUG_PRINTF (" bottom_class = %s, upper = %s\n",
(bottom_class ? bottom_class->name : NULL),
(upper ? upper->name : NULL));
- tree = prev = objc_calloc (1, sizeof (objc_class_tree));
+ superclass = class_superclass_of_class (bottom_class);
+
+ prev = objc_calloc (1, sizeof (objc_class_tree));
prev->class = bottom_class;
+ if (superclass == upper)
+ return prev;
+
while (superclass != upper)
{
tree = objc_calloc (1, sizeof (objc_class_tree));
@@ -201,23 +228,23 @@ create_tree_of_subclasses_inherited_from (Class bottom_class, Class upper)
}
/* Insert the `class' into the proper place in the `tree' class
- hierarchy. This function returns a new tree if the class has been
+ hierarchy. This function returns a new tree if the class has been
successfully inserted into the tree or NULL if the class is not
- part of the classes hierarchy described by `tree'. This function is
- private to objc_tree_insert_class (), you should not call it
+ part of the classes hierarchy described by `tree'. This function
+ is private to objc_tree_insert_class (), you should not call it
directly. */
static objc_class_tree *
__objc_tree_insert_class (objc_class_tree *tree, Class class)
{
- DEBUG_PRINTF ("__objc_tree_insert_class: tree = %x, class = %s\n",
- tree, class->name);
+ DEBUG_PRINTF ("__objc_tree_insert_class: tree = %p (root: %s), class = %s\n",
+ tree, ((tree && tree->class) ? tree->class->name : "Nil"), class->name);
if (tree == NULL)
return create_tree_of_subclasses_inherited_from (class, NULL);
else if (class == tree->class)
{
/* `class' has been already inserted. */
- DEBUG_PRINTF ("1. class %s was previously inserted\n", class->name);
+ DEBUG_PRINTF (" 1. class %s was previously inserted\n", class->name);
return tree;
}
else if (class_superclass_of_class (class) == tree->class)
@@ -234,7 +261,7 @@ __objc_tree_insert_class (objc_class_tree *tree, Class class)
the tree. */
if (((objc_class_tree *) list->head)->class == class)
{
- DEBUG_PRINTF ("2. class %s was previously inserted\n",
+ DEBUG_PRINTF (" 2. class %s was previously inserted\n",
class->name);
return tree;
}
@@ -246,7 +273,7 @@ __objc_tree_insert_class (objc_class_tree *tree, Class class)
node = objc_calloc (1, sizeof (objc_class_tree));
node->class = class;
tree->subclasses = list_cons (node, tree->subclasses);
- DEBUG_PRINTF ("3. class %s inserted\n", class->name);
+ DEBUG_PRINTF (" 3. class %s inserted\n", class->name);
return tree;
}
else
@@ -272,7 +299,7 @@ __objc_tree_insert_class (objc_class_tree *tree, Class class)
since nothing has been changed. */
subclasses->head
= __objc_tree_insert_class (subclasses->head, class);
- DEBUG_PRINTF ("4. class %s inserted\n", class->name);
+ DEBUG_PRINTF (" 4. class %s inserted\n", class->name);
return tree;
}
}
@@ -284,7 +311,7 @@ __objc_tree_insert_class (objc_class_tree *tree, Class class)
objc_class_tree *new_tree
= create_tree_of_subclasses_inherited_from (class, tree->class);
tree->subclasses = list_cons (new_tree, tree->subclasses);
- DEBUG_PRINTF ("5. class %s inserted\n", class->name);
+ DEBUG_PRINTF (" 5. class %s inserted\n", class->name);
return tree;
}
}
@@ -296,27 +323,26 @@ objc_tree_insert_class (Class class)
{
struct objc_list *list_node;
objc_class_tree *tree;
-
+
list_node = __objc_class_tree_list;
while (list_node)
{
+ /* Try to insert the class in this class hierarchy. */
tree = __objc_tree_insert_class (list_node->head, class);
if (tree)
{
list_node->head = tree;
- break;
+ return;
}
else
list_node = list_node->tail;
}
-
- /* If the list was finished but the class hasn't been inserted,
- insert it here. */
- if (! list_node)
- {
- __objc_class_tree_list = list_cons (NULL, __objc_class_tree_list);
- __objc_class_tree_list->head = __objc_tree_insert_class (NULL, class);
- }
+
+ /* If the list was finished but the class hasn't been inserted, we
+ don't have an existing class hierarchy that can accomodate it.
+ Create a new one. */
+ __objc_class_tree_list = list_cons (NULL, __objc_class_tree_list);
+ __objc_class_tree_list->head = __objc_tree_insert_class (NULL, class);
}
/* Traverse tree in preorder. Used to send +load. */
@@ -359,56 +385,67 @@ __objc_tree_print (objc_class_tree *tree, int level)
#endif
/* Walks on a linked list of methods in the reverse order and executes
- all the methods corresponding to `op' selector. Walking in the
- reverse order assures the +load of class is executed first and then
- +load of categories because of the way in which categories are
- added to the class methods. */
+ all the methods corresponding to the `+load' selector. Walking in
+ the reverse order assures the +load of class is executed first and
+ then +load of categories because of the way in which categories are
+ added to the class methods. This function needs to be called with
+ the objc_runtime_mutex locked. */
static void
-__objc_send_message_in_list (struct objc_method_list *method_list, Class class, SEL op)
+__objc_send_load_using_method_list (struct objc_method_list *method_list, Class class)
{
+ static SEL load_selector = 0;
int i;
- if (! method_list)
+ if (!method_list)
return;
- /* First execute the `op' message in the following method lists. */
- __objc_send_message_in_list (method_list->method_next, class, op);
+ /* This needs no lock protection because we are called with the
+ objc_runtime_mutex locked. */
+ if (!load_selector)
+ load_selector = sel_registerName ("load");
+
+ /* method_list is a linked list of method lists; since we're
+ executing in reverse order, we need to do the next list before we
+ do this one. */
+ __objc_send_load_using_method_list (method_list->method_next, class);
/* Search the method list. */
for (i = 0; i < method_list->method_count; i++)
{
struct objc_method *mth = &method_list->method_list[i];
- if (mth->method_name && sel_eq (mth->method_name, op)
+ /* We are searching for +load methods that we haven't executed
+ yet. */
+ if (mth->method_name && sel_eq (mth->method_name, load_selector)
&& ! objc_hash_is_key_in_hash (__objc_load_methods, mth->method_imp))
{
- /* Add this method into the +load hash table. */
+ /* Add this method into the +load hash table, so we won't
+ execute it again next time. */
objc_hash_add (&__objc_load_methods,
mth->method_imp,
mth->method_imp);
- DEBUG_PRINTF ("sending +load in class: %s\n", class->name);
-
- /* The method was found and wasn't previously executed. */
+ /* Call +load. */
+ DEBUG_PRINTF (" begin of [%s +load]\n", class->name);
(*mth->method_imp) ((id)class, mth->method_name);
+ DEBUG_PRINTF (" end of [%s +load]\n", class->name);
break;
}
}
}
+/* This function needs to be called with the objc_runtime_mutex
+ locked. */
static void
__objc_send_load (objc_class_tree *tree,
int level __attribute__ ((__unused__)))
{
- static SEL load_sel = 0;
Class class = tree->class;
struct objc_method_list *method_list = class->class_pointer->methods;
- if (! load_sel)
- load_sel = sel_registerName ("load");
-
- __objc_send_message_in_list (method_list, class, load_sel);
+ DEBUG_PRINTF ("+load: need to send load to class '%s'\n", class->name);
+ __objc_send_load_using_method_list (method_list, class);
}
static void
@@ -549,11 +586,11 @@ __objc_exec_class (struct objc_module *module)
struct objc_list **cell;
/* The table of selector references for this module. */
- SEL selectors = symtab->refs;
+ struct objc_selector *selectors = symtab->refs;
int i;
- DEBUG_PRINTF ("received module: %s\n", module->name);
+ DEBUG_PRINTF ("\n__objc_exec_class (%p) - start processing module...\n", module);
/* Check gcc version. */
init_check_module_version (module);
@@ -570,7 +607,9 @@ __objc_exec_class (struct objc_module *module)
__objc_init_selector_tables ();
__objc_init_class_tables ();
__objc_init_dispatch_tables ();
- __objc_class_tree_list = list_cons (NULL, __objc_class_tree_list);
+ duplicate_classes = objc_hash_new (8,
+ (hash_func_type)objc_hash_ptr,
+ objc_compare_ptrs);
__objc_load_methods = objc_hash_new (128,
(hash_func_type)objc_hash_ptr,
objc_compare_ptrs);
@@ -580,31 +619,20 @@ __objc_exec_class (struct objc_module *module)
previous_constructors = 1;
}
- /* Save the module pointer for later processing. (not currently
- used). */
+ /* Save the module pointer so that later we remember to call +load
+ on all classes and categories on it. */
objc_mutex_lock (__objc_runtime_mutex);
__objc_module_list = list_cons (module, __objc_module_list);
- /* Replace referenced selectors from names to SEL's. */
+ /* Replace referenced selectors from names to SELs. */
if (selectors)
{
- for (i = 0; selectors[i].sel_id; ++i)
- {
- const char *name, *type;
- name = (char *) selectors[i].sel_id;
- type = (char *) selectors[i].sel_types;
- /* Constructors are constant static data so we can safely
- store pointers to them in the runtime
- structures. is_const == YES. */
- __sel_register_typed_name (name, type,
- (struct objc_selector *) &(selectors[i]),
- YES);
- }
+ DEBUG_PRINTF (" registering selectors\n");
+ __objc_register_selectors_from_module (selectors);
}
/* Parse the classes in the load module and gather selector
information. */
- DEBUG_PRINTF ("gathering selectors from module: %s\n", module->name);
for (i = 0; i < symtab->cls_def_cnt; ++i)
{
Class class = (Class) symtab->defs[i];
@@ -613,19 +641,20 @@ __objc_exec_class (struct objc_module *module)
/* Make sure we have what we think. */
assert (CLS_ISCLASS (class));
assert (CLS_ISMETA (class->class_pointer));
- DEBUG_PRINTF ("phase 1, processing class: %s\n", class->name);
+ DEBUG_PRINTF (" installing class '%s'\n", class->name);
/* Initialize the subclass list to be NULL. In some cases it
isn't and this crashes the program. */
class->subclass_list = NULL;
- __objc_init_class (class);
-
- /* Check to see if the superclass is known in this point. If
- it's not add the class to the unresolved_classes list. */
- if (superclass && ! objc_getClass (superclass))
- unresolved_classes = list_cons (class, unresolved_classes);
- }
+ if (__objc_init_class (class))
+ {
+ /* Check to see if the superclass is known in this point. If
+ it's not add the class to the unresolved_classes list. */
+ if (superclass && ! objc_getClass (superclass))
+ unresolved_classes = list_cons (class, unresolved_classes);
+ }
+ }
/* Process category information from the module. */
for (i = 0; i < symtab->cat_def_cnt; ++i)
@@ -637,11 +666,7 @@ __objc_exec_class (struct objc_module *module)
methods. */
if (class)
{
-
- DEBUG_PRINTF ("processing categories from (module,object): %s, %s\n",
- module->name,
- class->name);
-
+ DEBUG_PRINTF (" installing category '%s (%s)'\n", category->class_name, category->category_name);
/* Do instance methods. */
if (category->instance_methods)
class_add_method_list (class, category->instance_methods);
@@ -663,6 +688,7 @@ __objc_exec_class (struct objc_module *module)
}
else
{
+ DEBUG_PRINTF (" delaying installation of category '%s (%s)'\n", category->class_name, category->category_name);
/* The object to which the category methods belong can't be
found. Save the information. */
unclaimed_categories = list_cons (category, unclaimed_categories);
@@ -683,9 +709,7 @@ __objc_exec_class (struct objc_module *module)
if (class)
{
- DEBUG_PRINTF ("attaching stored categories to object: %s\n",
- class->name);
-
+ DEBUG_PRINTF (" installing (delayed) category '%s (%s)'\n", category->class_name, category->category_name);
list_remove_head (cell);
if (category->instance_methods)
@@ -725,19 +749,26 @@ __objc_exec_class (struct objc_module *module)
"resolving the class links" at this point, which will setup all
the class/superclass pointers. */
if (!unresolved_classes && objc_getClass ("Object"))
- __objc_resolve_class_links ();
+ {
+ DEBUG_PRINTF (" resolving class links\n");
+ __objc_resolve_class_links ();
+ }
objc_mutex_unlock (__objc_runtime_mutex);
+
+ DEBUG_PRINTF ("__objc_exec_class (%p) - finished processing module...\n\n", module);
}
+/* This function needs to be called with the objc_runtime_mutex
+ locked. */
static void
objc_send_load (void)
{
- if (! __objc_module_list)
+ if (!__objc_module_list)
return;
/* Try to find out if all the classes loaded so far also have their
- superclasses known to the runtime. We suppose that the objects
+ superclasses known to the runtime. We suppose that the objects
that are allocated in the +load method are in general of a class
declared in the same module. */
if (unresolved_classes)
@@ -755,7 +786,7 @@ objc_send_load (void)
/* If we still have classes for whom we don't have yet their
super classes known to the runtime we don't send the +load
- messages. */
+ messages (and call the load callback) yet. */
if (unresolved_classes)
return;
}
@@ -766,7 +797,7 @@ objc_send_load (void)
return;
/* Iterate over all modules in the __objc_module_list and call on
- them the __objc_create_classes_tree function. This function
+ them the __objc_create_classes_tree function. This function
creates a tree of classes that resembles the class hierarchy. */
list_mapcar (__objc_module_list,
(void (*) (void *)) __objc_create_classes_tree);
@@ -784,7 +815,11 @@ objc_send_load (void)
list_remove_head (&__objc_class_tree_list);
}
- list_mapcar (__objc_module_list, (void (*) (void *)) __objc_call_callback);
+ /* For each module, call the _objc_load_callback if any is
+ defined. */
+ list_mapcar (__objc_module_list, (void (*) (void *)) __objc_call_load_callback);
+
+ /* Empty the list of modules. */
list_free (__objc_module_list);
__objc_module_list = NULL;
}
@@ -802,38 +837,65 @@ __objc_create_classes_tree (struct objc_module *module)
{
Class class = (Class) symtab->defs[i];
- objc_tree_insert_class (class);
+ if (!objc_hash_is_key_in_hash (duplicate_classes, class))
+ objc_tree_insert_class (class);
}
-}
-
-static void
-__objc_call_callback (struct objc_module *module)
-{
- /* The runtime mutex is locked at this point. */
- struct objc_symtab *symtab = module->symtab;
- int i;
- /* Iterate thru classes defined in this module and call the callback
- for each one. */
- for (i = 0; i < symtab->cls_def_cnt; i++)
- {
- Class class = (Class) symtab->defs[i];
-
- /* Call the _objc_load_callback for this class. */
- if (_objc_load_callback)
- _objc_load_callback (class, 0);
- }
-
- /* Call the _objc_load_callback for categories. Don't register the
- instance methods as class methods for categories to root classes
- since they were already added in the class. */
- for (i = 0; i < symtab->cat_def_cnt; i++)
+ /* Now iterate over "claimed" categories too (ie, categories that
+ extend a class that has already been loaded by the runtime), and
+ insert them in the classes tree hiearchy too. Otherwise, if you
+ add a category, its +load method would not be called if the class
+ is already loaded in the runtime. It the category is
+ "unclaimed", ie, we haven't loaded the main class yet, postpone
+ sending +load as we want to execute +load from the class before
+ we execute the one from the category. */
+ for (i = 0; i < symtab->cat_def_cnt; ++i)
{
struct objc_category *category = symtab->defs[i + symtab->cls_def_cnt];
Class class = objc_getClass (category->class_name);
+
+ /* If the class for the category exists then append its
+ methods. */
+ if (class)
+ objc_tree_insert_class (class);
+ }
+}
- if (_objc_load_callback)
- _objc_load_callback (class, category);
+static void
+__objc_call_load_callback (struct objc_module *module)
+{
+ if (_objc_load_callback)
+ {
+ /* The runtime mutex is locked at this point. */
+ struct objc_symtab *symtab = module->symtab;
+ int i;
+
+ /* Iterate thru classes defined in this module and call the callback
+ for each one. */
+ for (i = 0; i < symtab->cls_def_cnt; i++)
+ {
+ Class class = (Class) symtab->defs[i];
+
+ if (!objc_hash_is_key_in_hash (duplicate_classes, class))
+ {
+ /* Call the _objc_load_callback for this class. */
+ DEBUG_PRINTF (" calling the load callback for class '%s'\n", class->name);
+ _objc_load_callback (class, 0);
+ }
+ }
+
+ /* Call the _objc_load_callback for categories. Don't register
+ the instance methods as class methods for categories to root
+ classes since they were already added in the class. */
+ for (i = 0; i < symtab->cat_def_cnt; i++)
+ {
+ struct objc_category *category = symtab->defs[i + symtab->cls_def_cnt];
+ Class class = objc_getClass (category->class_name);
+
+ DEBUG_PRINTF (" calling the load callback for category '%s (%s)'\n",
+ category->class_name, category->category_name);
+ _objc_load_callback (class, category);
+ }
}
}
@@ -848,27 +910,41 @@ init_check_module_version (struct objc_module *module)
}
}
-/* __objc_init_class must be called with __objc_runtime_mutex already locked. */
-void
+/* __objc_init_class must be called with __objc_runtime_mutex already
+ locked. Return YES if the class could be setup; return NO if the
+ class could not be setup because a class with the same name already
+ exists. */
+BOOL
__objc_init_class (Class class)
{
/* Store the class in the class table and assign class numbers. */
- __objc_add_class_to_hash (class);
-
- /* Register all of the selectors in the class and meta class. */
- __objc_register_selectors_from_class (class);
- __objc_register_selectors_from_class ((Class) class->class_pointer);
-
- /* Install the fake dispatch tables. */
- __objc_install_premature_dtable (class);
- __objc_install_premature_dtable (class->class_pointer);
-
- /* Register the instance methods as class methods, this is only done
- for root classes. */
- __objc_register_instance_methods_to_class (class);
+ if (__objc_add_class_to_hash (class))
+ {
+ /* Register all of the selectors in the class and meta class. */
+ __objc_register_selectors_from_class (class);
+ __objc_register_selectors_from_class ((Class) class->class_pointer);
+
+ /* Install the fake dispatch tables. */
+ __objc_install_premature_dtable (class);
+ __objc_install_premature_dtable (class->class_pointer);
+
+ /* Register the instance methods as class methods, this is only
+ done for root classes. */
+ __objc_register_instance_methods_to_class (class);
+
+ if (class->protocols)
+ __objc_init_protocols (class->protocols);
- if (class->protocols)
- __objc_init_protocols (class->protocols);
+ return YES;
+ }
+ else
+ {
+ /* The module contains a duplicate class. Remember it so that
+ we will ignore it later. */
+ DEBUG_PRINTF (" duplicate class '%s' - will be ignored\n", class->name);
+ objc_hash_add (&duplicate_classes, class, class);
+ return NO;
+ }
}
/* __objc_init_protocol must be called with __objc_runtime_mutex
diff --git a/libobjc/ivars.c b/libobjc/ivars.c
index 7527df804d2..6111a03ea16 100644
--- a/libobjc/ivars.c
+++ b/libobjc/ivars.c
@@ -212,7 +212,7 @@ struct objc_ivar ** class_copyIvarList (Class class_, unsigned int *numberOfRetu
BOOL
class_addIvar (Class class_, const char * ivar_name, size_t size,
- unsigned char alignment, const char *type)
+ unsigned char log_2_of_alignment, const char *type)
{
struct objc_ivar_list *ivars;
@@ -270,6 +270,7 @@ class_addIvar (Class class_, const char * ivar_name, size_t size,
size. */
{
struct objc_ivar *ivar = &(ivars->ivar_list[ivars->ivar_count - 1]);
+ unsigned int alignment = 1 << log_2_of_alignment;
int misalignment;
ivar->ivar_name = objc_malloc (strlen (ivar_name) + 1);
diff --git a/libobjc/linking.m b/libobjc/linking.m
index 4438a668ce4..75fe7d3e3dc 100644
--- a/libobjc/linking.m
+++ b/libobjc/linking.m
@@ -25,7 +25,6 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#include "objc-private/common.h"
#include <objc/Object.h>
-#include <objc/NXConstStr.h>
/* Generate references to Object class since it is needed by the
runtime system to run correctly. */
diff --git a/libobjc/objc-private/accessors.h b/libobjc/objc-private/accessors.h
index a7bcca22649..570ae7a8555 100644
--- a/libobjc/objc-private/accessors.h
+++ b/libobjc/objc-private/accessors.h
@@ -25,16 +25,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#ifndef __objc_private_accessors_INCLUDE_GNU
#define __objc_private_accessors_INCLUDE_GNU
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
/* This function needs to be called at startup by init.c. */
void
__objc_accessors_init (void);
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
#endif /* not __objc_private_accessors_INCLUDE_GNU */
diff --git a/libobjc/objc-private/common.h b/libobjc/objc-private/common.h
index 1642faa5139..4f4ec5cd077 100644
--- a/libobjc/objc-private/common.h
+++ b/libobjc/objc-private/common.h
@@ -26,13 +26,24 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#define __objc_private_common_INCLUDE_GNU
/* This file contains definitions that should be included by all .c
- and .m files in libobjc.
-*/
+ and .m files in libobjc. */
/* This variable allows the public headers to determine when they are
being included by a file inside libobjc itself, or when they are
- being included by an external file.
-*/
+ being included by an external file. */
#define GNU_LIBOBJC_COMPILING_LIBOBJC_ITSELF 1
+/* When debugging libobjc, add
+
+ #define DEBUG 1
+
+ at the very beginning of a file in libobjc (before including this file) to turn
+ on DEBUG_PRINTF(). */
+#ifdef DEBUG
+#include <stdio.h>
+#define DEBUG_PRINTF(format, args...) printf (format, ## args)
+#else
+#define DEBUG_PRINTF(format, args...)
+#endif
+
#endif /* __objc_private_common_INCLUDE_GNU */
diff --git a/libobjc/objc-private/hash.h b/libobjc/objc-private/hash.h
index ba4c4943438..c330d618e51 100644
--- a/libobjc/objc-private/hash.h
+++ b/libobjc/objc-private/hash.h
@@ -30,10 +30,6 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#include <stddef.h>
#include <string.h>
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
/*
* This data structure is used to hold items
* stored in a hash table. Each node holds
@@ -202,10 +198,4 @@ objc_compare_strings (const void *k1, const void *k2)
return ! strcmp ((const char *) k1, (const char *) k2);
}
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-
#endif /* not __hash_INCLUDE_GNU */
diff --git a/libobjc/objc-private/module-abi-8.h b/libobjc/objc-private/module-abi-8.h
index 3ed836c518f..0c9574bb499 100644
--- a/libobjc/objc-private/module-abi-8.h
+++ b/libobjc/objc-private/module-abi-8.h
@@ -48,10 +48,16 @@ struct objc_static_instances
struct objc_symtab
{
unsigned long sel_ref_cnt; /* Unused (always set to 0). */
- SEL refs; /* The table of selectors referenced in
+ struct objc_selector *refs; /* The table of selectors referenced in
this module. This is terminated by a
selector with NULL sel_id and NULL
- sel_types. */
+ sel_types. Note that we use the type
+ 'struct objc_selector *' and not
+ 'SEL' (which is 'const struct
+ objc_selector *') because the sel_id
+ of these selectors is patched up by
+ the runtime when the module is
+ loaded. */
unsigned short cls_def_cnt; /* Number of classes compiled (defined)
in the module. */
unsigned short cat_def_cnt; /* Number of categories compiled
diff --git a/libobjc/objc-private/objc-list.h b/libobjc/objc-private/objc-list.h
index b78f4c1347f..989b9c9d4cb 100644
--- a/libobjc/objc-private/objc-list.h
+++ b/libobjc/objc-private/objc-list.h
@@ -1,5 +1,5 @@
/* Generic single linked list to keep various information
- Copyright (C) 1993, 1994, 1996, 2009 Free Software Foundation, Inc.
+ Copyright (C) 1993, 1994, 1996, 2009, 2010 Free Software Foundation, Inc.
Contributed by Kresten Krab Thorup.
This file is part of GCC.
@@ -23,77 +23,72 @@ a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */
-
#ifndef __GNU_OBJC_LIST_H
#define __GNU_OBJC_LIST_H
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-struct objc_list {
+struct objc_list
+{
void *head;
struct objc_list *tail;
};
-/* Return a cons cell produced from (head . tail) */
-
+/* Return a cons cell produced from (head . tail). */
static inline struct objc_list*
-list_cons(void* head, struct objc_list* tail)
+list_cons (void* head, struct objc_list* tail)
{
struct objc_list* cell;
- cell = (struct objc_list*)objc_malloc(sizeof(struct objc_list));
+ cell = (struct objc_list*)objc_malloc (sizeof (struct objc_list));
cell->head = head;
cell->tail = tail;
return cell;
}
-/* Remove the element at the head by replacing it by its successor */
-
+/* Remove the element at the head by replacing it by its
+ successor. */
static inline void
-list_remove_head(struct objc_list** list)
+list_remove_head (struct objc_list** list)
{
if ((*list)->tail)
{
- struct objc_list* tail = (*list)->tail; /* fetch next */
- *(*list) = *tail; /* copy next to list head */
- objc_free(tail); /* free next */
+ /* Fetch next. */
+ struct objc_list* tail = (*list)->tail;
+
+ /* Copy next to list head. */
+ *(*list) = *tail;
+
+ /* Free next. */
+ objc_free (tail);
}
- else /* only one element in list */
+ else
{
- objc_free(*list);
+ /* Inly one element in list. */
+ objc_free (*list);
(*list) = 0;
}
}
-/* Map FUNCTION over all elements in LIST */
-
+/* Map FUNCTION over all elements in LIST. */
static inline void
-list_mapcar(struct objc_list* list, void(*function)(void*))
+list_mapcar (struct objc_list* list, void(*function)(void*))
{
- while(list)
+ while (list)
{
- (*function)(list->head);
+ (*function) (list->head);
list = list->tail;
}
}
-/* Free list (backwards recursive) */
-
+/* Free list (backwards recursive). */
static inline void
-list_free(struct objc_list* list)
+list_free (struct objc_list* list)
{
if(list)
{
- list_free(list->tail);
- objc_free(list);
+ list_free (list->tail);
+ objc_free (list);
}
}
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
#endif /* not __GNU_OBJC_LIST_H */
diff --git a/libobjc/objc-private/objc-sync.h b/libobjc/objc-private/objc-sync.h
index e69d756d3ad..95eb28b30ed 100644
--- a/libobjc/objc-private/objc-sync.h
+++ b/libobjc/objc-private/objc-sync.h
@@ -25,17 +25,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#ifndef __objc_private_objc_sync_INCLUDE_GNU
#define __objc_private_objc_sync_INCLUDE_GNU
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
/* This function needs to be called at startup before @synchronized()
can be used. */
void
__objc_sync_init (void);
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
#endif /* not __objc_private_objc_sync_INCLUDE_GNU */
diff --git a/libobjc/objc-private/protocols.h b/libobjc/objc-private/protocols.h
index 49a2d92648f..87f8fc8487c 100644
--- a/libobjc/objc-private/protocols.h
+++ b/libobjc/objc-private/protocols.h
@@ -25,10 +25,6 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#ifndef __objc_private_protocols_INCLUDE_GNU
#define __objc_private_protocols_INCLUDE_GNU
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
/* This function needs to be called at startup by init.c. */
void
__objc_protocols_init (void);
@@ -39,8 +35,4 @@ __objc_protocols_init (void);
void
__objc_protocols_add_protocol (const char *name, Protocol *object);
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
#endif /* not __objc_private_protocols_INCLUDE_GNU */
diff --git a/libobjc/objc-private/runtime.h b/libobjc/objc-private/runtime.h
index ba01f576227..5406294f2c3 100644
--- a/libobjc/objc-private/runtime.h
+++ b/libobjc/objc-private/runtime.h
@@ -48,25 +48,21 @@ objc/runtime.h. */
#include <stddef.h> /* so noone else will get system versions */
#include <assert.h>
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-extern void __objc_add_class_to_hash(Class); /* (objc-class.c) */
-extern void __objc_init_class_tables(void); /* (objc-class.c) */
-extern void __objc_init_dispatch_tables(void); /* (objc-dispatch.c) */
-extern void __objc_install_premature_dtable(Class); /* (objc-dispatch.c) */
-extern void __objc_resolve_class_links(void); /* (objc-class.c) */
+extern BOOL __objc_add_class_to_hash (Class); /* (objc-class.c) */
+extern void __objc_init_class_tables (void); /* (objc-class.c) */
+extern void __objc_init_dispatch_tables (void); /* (objc-dispatch.c) */
+extern void __objc_install_premature_dtable (Class); /* (objc-dispatch.c) */
+extern void __objc_resolve_class_links (void); /* (objc-class.c) */
extern void __objc_update_dispatch_table_for_class (Class);/* (objc-msg.c) */
-extern int __objc_init_thread_system(void); /* thread.c */
-extern int __objc_fini_thread_system(void); /* thread.c */
-extern void __objc_init_class (Class class); /* init.c */
-extern void class_add_method_list(Class, struct objc_method_list *);
+extern int __objc_init_thread_system (void); /* thread.c */
+extern int __objc_fini_thread_system (void); /* thread.c */
+extern BOOL __objc_init_class (Class class); /* init.c */
+extern void class_add_method_list (Class, struct objc_method_list *);
/* Registering instance methods as class methods for root classes */
-extern void __objc_register_instance_methods_to_class(Class);
-extern struct objc_method * search_for_method_in_list(struct objc_method_list * list, SEL op);
+extern void __objc_register_instance_methods_to_class (Class);
+extern struct objc_method * search_for_method_in_list (struct objc_method_list * list, SEL op);
extern void
__objc_update_classes_with_methods (struct objc_method *method_a, struct objc_method *method_b); /* class.c */
@@ -77,17 +73,7 @@ extern objc_mutex_t __objc_runtime_mutex;
/* Number of threads which are alive. */
extern int __objc_runtime_threads_alive;
-#ifdef DEBUG
-#define DEBUG_PRINTF(format, args...) printf (format, ## args)
-#else
-#define DEBUG_PRINTF(format, args...)
-#endif
-
BOOL __objc_responds_to (id object, SEL sel); /* for internal use only! */
extern void __objc_generate_gc_type_description (Class);
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
#endif /* not __objc_private_runtime_INCLUDE_GNU */
diff --git a/libobjc/objc-private/sarray.h b/libobjc/objc-private/sarray.h
index f81b08e71e7..12fad921f28 100644
--- a/libobjc/objc-private/sarray.h
+++ b/libobjc/objc-private/sarray.h
@@ -1,5 +1,5 @@
/* Sparse Arrays for Objective C dispatch tables
- Copyright (C) 1993, 1995, 1996, 2004, 2009 Free Software Foundation, Inc.
+ Copyright (C) 1993, 1995, 1996, 2004, 2009, 2010 Free Software Foundation, Inc.
Contributed by Kresten Krab Thorup.
This file is part of GCC.
@@ -26,8 +26,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#ifndef __sarray_INCLUDE_GNU
#define __sarray_INCLUDE_GNU
-#define OBJC_SPARSE2 /* 2-level sparse array */
-/* #define OBJC_SPARSE3 */ /* 3-level sparse array */
+#define OBJC_SPARSE2 /* 2-level sparse array. */
+/* #define OBJC_SPARSE3 */ /* 3-level sparse array. */
#ifdef OBJC_SPARSE2
extern const char* __objc_sparse2_id;
@@ -39,42 +39,38 @@ extern const char* __objc_sparse3_id;
#include <stddef.h>
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
extern int nbuckets; /* for stats */
extern int nindices;
extern int narrays;
extern int idxsize;
-/* An unsigned integer of same size as a pointer */
-#define SIZET_BITS (sizeof(size_t)*8)
+/* An unsigned integer of same size as a pointer. */
+#define SIZET_BITS (sizeof (size_t) * 8)
-#if defined(__sparc__) || defined(OBJC_SPARSE2)
+#if defined (__sparc__) || defined (OBJC_SPARSE2)
#define PRECOMPUTE_SELECTORS
#endif
#ifdef OBJC_SPARSE3
-/* Buckets are 8 words each */
+/* Buckets are 8 words each. */
#define BUCKET_BITS 3
-#define BUCKET_SIZE (1<<BUCKET_BITS)
-#define BUCKET_MASK (BUCKET_SIZE-1)
+#define BUCKET_SIZE (1 << BUCKET_BITS)
+#define BUCKET_MASK (BUCKET_SIZE - 1)
-/* Indices are 16 words each */
+/* Indices are 16 words each. */
#define INDEX_BITS 4
-#define INDEX_SIZE (1<<INDEX_BITS)
-#define INDEX_MASK (INDEX_SIZE-1)
+#define INDEX_SIZE (1 << INDEX_BITS)
+#define INDEX_MASK (INDEX_SIZE - 1)
-#define INDEX_CAPACITY (BUCKET_SIZE*INDEX_SIZE)
+#define INDEX_CAPACITY (BUCKET_SIZE * INDEX_SIZE)
#else /* OBJC_SPARSE2 */
-/* Buckets are 32 words each */
+/* Buckets are 32 words each. */
#define BUCKET_BITS 5
-#define BUCKET_SIZE (1<<BUCKET_BITS)
-#define BUCKET_MASK (BUCKET_SIZE-1)
+#define BUCKET_SIZE (1 << BUCKET_BITS)
+#define BUCKET_MASK (BUCKET_SIZE - 1)
#endif /* OBJC_SPARSE2 */
@@ -82,51 +78,62 @@ typedef size_t sidx;
#ifdef PRECOMPUTE_SELECTORS
-struct soffset {
+struct soffset
+{
#ifdef OBJC_SPARSE3
- unsigned int unused : SIZET_BITS/4;
- unsigned int eoffset : SIZET_BITS/4;
- unsigned int boffset : SIZET_BITS/4;
- unsigned int ioffset : SIZET_BITS/4;
+ unsigned int unused : SIZET_BITS / 4;
+ unsigned int eoffset : SIZET_BITS / 4;
+ unsigned int boffset : SIZET_BITS / 4;
+ unsigned int ioffset : SIZET_BITS / 4;
#else /* OBJC_SPARSE2 */
#ifdef __sparc__
unsigned long boffset : (SIZET_BITS - 2) - BUCKET_BITS;
unsigned int eoffset : BUCKET_BITS;
unsigned int unused : 2;
#else
- unsigned int boffset : SIZET_BITS/2;
- unsigned int eoffset : SIZET_BITS/2;
+ unsigned int boffset : SIZET_BITS / 2;
+ unsigned int eoffset : SIZET_BITS / 2;
#endif
#endif /* OBJC_SPARSE2 */
};
-union sofftype {
+union sofftype
+{
struct soffset off;
sidx idx;
};
#endif /* not PRECOMPUTE_SELECTORS */
-union sversion {
+union sversion
+{
int version;
void *next_free;
};
-struct sbucket {
- void* elems[BUCKET_SIZE]; /* elements stored in array */
- union sversion version; /* used for copy-on-write */
+struct sbucket
+{
+ /* Elements stored in array. */
+ void* elems[BUCKET_SIZE];
+
+ /* Used for copy-on-write. */
+ union sversion version;
};
#ifdef OBJC_SPARSE3
-struct sindex {
+struct sindex
+{
struct sbucket* buckets[INDEX_SIZE];
- union sversion version; /* used for copy-on-write */
+
+ /* Used for copy-on-write. */
+ union sversion version;
};
#endif /* OBJC_SPARSE3 */
-struct sarray {
+struct sarray
+{
#ifdef OBJC_SPARSE3
struct sindex** indices;
struct sindex* empty_index;
@@ -134,49 +141,52 @@ struct sarray {
struct sbucket** buckets;
#endif /* OBJC_SPARSE2 */
struct sbucket* empty_bucket;
- union sversion version; /* used for copy-on-write */
+
+ /* Used for copy-on-write. */
+ union sversion version;
+
short ref_count;
struct sarray* is_copy_of;
size_t capacity;
};
-struct sarray* sarray_new(int, void* default_element);
-void sarray_free(struct sarray*);
-struct sarray* sarray_lazy_copy(struct sarray*);
-void sarray_realloc(struct sarray*, int new_size);
-void sarray_at_put(struct sarray*, sidx indx, void* elem);
-void sarray_at_put_safe(struct sarray*, sidx indx, void* elem);
+struct sarray* sarray_new (int, void* default_element);
+void sarray_free (struct sarray*);
+struct sarray* sarray_lazy_copy (struct sarray*);
+void sarray_realloc (struct sarray*, int new_size);
+void sarray_at_put (struct sarray*, sidx indx, void* elem);
+void sarray_at_put_safe (struct sarray*, sidx indx, void* elem);
-struct sarray* sarray_hard_copy(struct sarray*); /* ... like the name? */
-void sarray_remove_garbage(void);
+struct sarray* sarray_hard_copy (struct sarray*); /* ... like the name ? */
+void sarray_remove_garbage (void);
#ifdef PRECOMPUTE_SELECTORS
-/* Transform soffset values to ints and vica verca */
+/* Transform soffset values to ints and vice versa. */
static inline unsigned int
-soffset_decode(sidx indx)
+soffset_decode (sidx indx)
{
union sofftype x;
x.idx = indx;
#ifdef OBJC_SPARSE3
return x.off.eoffset
- + (x.off.boffset*BUCKET_SIZE)
- + (x.off.ioffset*INDEX_CAPACITY);
+ + (x.off.boffset * BUCKET_SIZE)
+ + (x.off.ioffset * INDEX_CAPACITY);
#else /* OBJC_SPARSE2 */
- return x.off.eoffset + (x.off.boffset*BUCKET_SIZE);
+ return x.off.eoffset + (x.off.boffset * BUCKET_SIZE);
#endif /* OBJC_SPARSE2 */
}
static inline sidx
-soffset_encode(size_t offset)
+soffset_encode (size_t offset)
{
union sofftype x;
- x.off.eoffset = offset%BUCKET_SIZE;
+ x.off.eoffset = offset % BUCKET_SIZE;
#ifdef OBJC_SPARSE3
- x.off.boffset = (offset/BUCKET_SIZE)%INDEX_SIZE;
- x.off.ioffset = offset/INDEX_CAPACITY;
+ x.off.boffset = (offset / BUCKET_SIZE) % INDEX_SIZE;
+ x.off.ioffset = offset / INDEX_CAPACITY;
#else /* OBJC_SPARSE2 */
- x.off.boffset = offset/BUCKET_SIZE;
+ x.off.boffset = offset / BUCKET_SIZE;
#endif
return (sidx)x.idx;
}
@@ -184,56 +194,50 @@ soffset_encode(size_t offset)
#else /* not PRECOMPUTE_SELECTORS */
static inline size_t
-soffset_decode(sidx indx)
+soffset_decode (sidx indx)
{
return indx;
}
static inline sidx
-soffset_encode(size_t offset)
+soffset_encode (size_t offset)
{
return offset;
}
#endif /* not PRECOMPUTE_SELECTORS */
-/* Get element from the Sparse array `array' at offset `indx' */
-
-static inline void* sarray_get(struct sarray* array, sidx indx)
+/* Get element from the Sparse array `array' at offset `indx'. */
+static inline void* sarray_get (struct sarray* array, sidx indx)
{
#ifdef PRECOMPUTE_SELECTORS
union sofftype x;
x.idx = indx;
#ifdef OBJC_SPARSE3
- return
- array->
- indices[x.off.ioffset]->
- buckets[x.off.boffset]->
- elems[x.off.eoffset];
+ return array->
+ indices[x.off.ioffset]->
+ buckets[x.off.boffset]->
+ elems[x.off.eoffset];
#else /* OBJC_SPARSE2 */
return array->buckets[x.off.boffset]->elems[x.off.eoffset];
#endif /* OBJC_SPARSE2 */
#else /* not PRECOMPUTE_SELECTORS */
#ifdef OBJC_SPARSE3
return array->
- indices[indx/INDEX_CAPACITY]->
- buckets[(indx/BUCKET_SIZE)%INDEX_SIZE]->
- elems[indx%BUCKET_SIZE];
+ indices[indx / INDEX_CAPACITY]->
+ buckets[(indx / BUCKET_SIZE) % INDEX_SIZE]->
+ elems[indx % BUCKET_SIZE];
#else /* OBJC_SPARSE2 */
- return array->buckets[indx/BUCKET_SIZE]->elems[indx%BUCKET_SIZE];
+ return array->buckets[indx / BUCKET_SIZE]->elems[indx % BUCKET_SIZE];
#endif /* not OBJC_SPARSE3 */
#endif /* not PRECOMPUTE_SELECTORS */
}
-static inline void* sarray_get_safe(struct sarray* array, sidx indx)
+static inline void* sarray_get_safe (struct sarray* array, sidx indx)
{
- if(soffset_decode(indx) < array->capacity)
- return sarray_get(array, indx);
+ if (soffset_decode (indx) < array->capacity)
+ return sarray_get (array, indx);
else
return (array->empty_bucket->elems[0]);
}
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
#endif /* __sarray_INCLUDE_GNU */
diff --git a/libobjc/objc-private/selector.h b/libobjc/objc-private/selector.h
index 66413a946fe..490e17105a5 100644
--- a/libobjc/objc-private/selector.h
+++ b/libobjc/objc-private/selector.h
@@ -25,10 +25,6 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#ifndef __objc_private_selector_INCLUDE_GNU
#define __objc_private_selector_INCLUDE_GNU
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
/* Private runtime functions that may go away or be rewritten or
replaced. */
@@ -43,6 +39,7 @@ void __objc_register_selectors_from_class(Class);
void __objc_register_selectors_from_list (struct objc_method_list *);
void __objc_register_selectors_from_description_list
(struct objc_method_description_list *method_list);
+void __objc_register_selectors_from_module (struct objc_selector *selectors);
/* Return whether a selector is mapped or not ("mapped" meaning that
it has been inserted into the selector table). This is private as
@@ -57,12 +54,4 @@ BOOL sel_is_mapped (SEL aSel);
SEL
sel_get_any_uid (const char *name);
-SEL
-__sel_register_typed_name (const char *name, const char *types,
- struct objc_selector *orig, BOOL is_const);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
#endif /* not __objc_private_selector_INCLUDE_GNU */
diff --git a/libobjc/objc/runtime.h b/libobjc/objc/runtime.h
index 8d380156e41..551c348d307 100644
--- a/libobjc/objc/runtime.h
+++ b/libobjc/objc/runtime.h
@@ -175,12 +175,13 @@ object_getClass (id object)
"<null selector>". */
objc_EXPORT const char *sel_getName (SEL selector);
-/* Return the type of a given selector.
+/* Return the type of a given selector. Return NULL if selector is
+ NULL.
Compatibility Note: the Apple/NeXT runtime has untyped selectors,
so it does not have this function, which is specific to the GNU
Runtime. */
-objc_EXPORT const char *sel_getType (SEL selector);
+objc_EXPORT const char *sel_getTypeEncoding (SEL selector);
/* This is the same as sel_registerName (). Please use
sel_registerName () instead. */
@@ -188,11 +189,16 @@ objc_EXPORT SEL sel_getUid (const char *name);
/* Register a selector with a given name (but unspecified types). If
you know the types, it is better to call sel_registerTypedName().
- If a selector with this name already exists, it is returned. */
+ If a selector with this name and no types already exists, it is
+ returned. Note that this function should really be called
+ 'objc_registerSelector'. Return NULL if 'name' is NULL. */
objc_EXPORT SEL sel_registerName (const char *name);
/* Register a selector with a given name and types. If a selector
- with this name and types already exists, it is returned.
+ with this name and types already exists, it is returned. Note that
+ this function should really be called 'objc_registerTypedSelector',
+ and it's called 'sel_registerTypedName' only for consistency with
+ 'sel_registerName'. Return NULL if 'name' is NULL.
Compatibility Note: the Apple/NeXT runtime has untyped selectors,
so it does not have this function, which is specific to the GNU
@@ -203,6 +209,37 @@ objc_EXPORT SEL sel_registerTypedName (const char *name, const char *type);
if not. */
objc_EXPORT BOOL sel_isEqual (SEL first_selector, SEL second_selector);
+/* Return all the selectors with the supplied name. In the GNU
+ runtime, selectors are typed and there may be multiple selectors
+ with the same name but a different type. The return value of the
+ function is a pointer to an area, allocated with malloc(), that
+ contains all the selectors with the supplier name known to the
+ runtime. The list is terminated by NULL. Optionally, if you pass
+ a non-NULL 'numberOfReturnedSelectors' pointer, the unsigned int
+ that it points to will be filled with the number of selectors
+ returned.
+
+ Compatibility Note: the Apple/NeXT runtime has untyped selectors,
+ so it does not have this function, which is specific to the GNU
+ Runtime. */
+objc_EXPORT SEL * sel_copyTypedSelectorList (const char *name,
+ unsigned int *numberOfReturnedSelectors);
+
+/* Return a selector with name 'name' and a non-zero type encoding, if
+ any such selector is registered with the runtime. If there is no
+ such selector, NULL is returned. Return NULL if 'name' is NULL.
+
+ This is useful if you have the name of the selector, and would
+ really like to get a selector for it that includes the type
+ encoding. Unfortunately, if the program contains multiple selector
+ with the same name but different types, sel_getTypedSelector
+ returns a random one of them, which may not be the right one.
+
+ Compatibility Note: the Apple/NeXT runtime has untyped selectors,
+ so it does not have this function, which is specific to the GNU
+ Runtime. */
+objc_EXPORT SEL sel_getTypedSelector (const char *name);
+
/** Implementation: the following functions are in objects.c. */
@@ -315,14 +352,16 @@ objc_EXPORT Ivar * class_copyIvarList (Class class_, unsigned int *numberOfRetur
using objc_allocateClassPair() and has not been registered with the
runtime using objc_registerClassPair() yet. You can not add
instance variables to classes already registered with the runtime.
- 'size' is the size of the instance variable, 'alignment' the
- alignment, and 'type' the type encoding of the variable type. You
- can use sizeof(), __alignof__() and @encode() to determine the
- right 'size', 'alignment' and 'type' for your instance variable.
- For example, to add an instance variable name "my_variable" and of
- type 'id', you can use:
-
- class_addIvar (class, "my_variable", sizeof (id), __alignof__ (id),
+ 'size' is the size of the instance variable, 'log_2_of_alignment'
+ the alignment as a power of 2 (so 0 means alignment to a 1 byte
+ boundary, 1 means alignment to a 2 byte boundary, 2 means alignment
+ to a 4 byte boundary, etc), and 'type' the type encoding of the
+ variable type. You can use sizeof(), log2(__alignof__()) and
+ @encode() to determine the right 'size', 'alignment' and 'type' for
+ your instance variable. For example, to add an instance variable
+ name "my_variable" and of type 'id', you can use:
+
+ class_addIvar (class, "my_variable", sizeof (id), log2 ( __alignof__ (id)),
@encode (id));
Return YES if the variable was added, and NO if not. In
@@ -331,7 +370,7 @@ objc_EXPORT Ivar * class_copyIvarList (Class class_, unsigned int *numberOfRetur
'type' is NULL, or 'size' is 0.
*/
objc_EXPORT BOOL class_addIvar (Class class_, const char * ivar_name, size_t size,
- unsigned char alignment, const char *type);
+ unsigned char log_2_of_alignment, const char *type);
/* Return the name of the property. Return NULL if 'property' is
NULL. */
@@ -768,7 +807,11 @@ objc_EXPORT Protocol **objc_copyProtocolList (unsigned int *numberOfReturnedProt
objc_EXPORT BOOL class_addProtocol (Class class_, Protocol *protocol);
/* Return YES if the class 'class_' conforms to Protocol 'protocol',
- and NO if not. */
+ and NO if not. This function does not check superclasses; if you
+ want to check for superclasses (in the way that [NSObject
+ +conformsToProtocol:] does) you need to iterate over the class
+ hierarchy using class_getSuperclass(), and call
+ class_conformsToProtocol() for each of them. */
objc_EXPORT BOOL class_conformsToProtocol (Class class_, Protocol *protocol);
/* Return all the protocols that the class conforms to. The return
@@ -777,7 +820,9 @@ objc_EXPORT BOOL class_conformsToProtocol (Class class_, Protocol *protocol);
class. It does not include protocols adopted by superclasses. The
list is terminated by NULL. Optionally, if you pass a non-NULL
'numberOfReturnedProtocols' pointer, the unsigned int that it
- points to will be filled with the number of protocols returned. */
+ points to will be filled with the number of protocols returned.
+ This function does not return protocols that superclasses conform
+ to. */
objc_EXPORT Protocol **class_copyProtocolList (Class class_, unsigned int *numberOfReturnedProtocols);
/* Return YES if protocol 'protocol' conforms to protocol
diff --git a/libobjc/selector.c b/libobjc/selector.c
index f63ceeb0f98..4110df2662b 100644
--- a/libobjc/selector.c
+++ b/libobjc/selector.c
@@ -31,6 +31,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#include "objc-private/runtime.h"
#include "objc-private/sarray.h"
#include "objc-private/selector.h"
+#include <stdlib.h> /* For malloc. */
/* Initial selector hash table size. Value doesn't matter much. */
#define SELECTOR_HASH_SIZE 128
@@ -43,6 +44,11 @@ static cache_ptr __objc_selector_hash = 0; /* name -> uid !T:MUTEX */
/* Number of selectors stored in each of the above tables. */
unsigned int __objc_selector_max_index = 0; /* !T:MUTEX */
+/* Forward-declare an internal function. */
+static SEL
+__sel_register_typed_name (const char *name, const char *types,
+ struct objc_selector *orig, BOOL is_const);
+
void __objc_init_selector_tables (void)
{
__objc_selector_array = sarray_new (SELECTOR_HASH_SIZE, 0);
@@ -53,6 +59,29 @@ void __objc_init_selector_tables (void)
(compare_func_type) objc_compare_strings);
}
+/* Register a bunch of selectors from the table of selectors in a
+ module. 'selectors' should not be NULL. The list is terminated by
+ a selectors with a NULL sel_id. The selectors are assumed to
+ contain the 'name' in the sel_id field; this is replaced with the
+ final selector id after they are registered. */
+void
+__objc_register_selectors_from_module (struct objc_selector *selectors)
+{
+ int i;
+
+ for (i = 0; selectors[i].sel_id; ++i)
+ {
+ const char *name, *type;
+ name = (char *) selectors[i].sel_id;
+ type = (char *) selectors[i].sel_types;
+ /* Constructors are constant static data and we can safely store
+ pointers to them in the runtime structures, so we set
+ is_const == YES. */
+ __sel_register_typed_name (name, type, (struct objc_selector *) &(selectors[i]),
+ /* is_const */ YES);
+ }
+}
+
/* This routine is given a class and records all of the methods in its
class structure in the record table. */
void
@@ -222,7 +251,11 @@ sel_types_match (const char *t1, const char *t2)
return NO;
}
-/* Return selector representing name. */
+/* Return selector representing name. In the Modern API, you'd
+ normally use sel_registerTypedName() for this, which does the same
+ but would register the selector with the runtime if not registered
+ yet (if you only want to check for selectors without registering,
+ use sel_copyTypedSelectorList()). */
SEL
sel_get_typed_uid (const char *name, const char *types)
{
@@ -262,7 +295,8 @@ sel_get_typed_uid (const char *name, const char *types)
}
/* Return selector representing name; prefer a selector with non-NULL
- type. */
+ type. In the Modern API, sel_getTypedSelector() is similar but
+ returns NULL if a typed selector couldn't be found. */
SEL
sel_get_any_typed_uid (const char *name)
{
@@ -319,6 +353,95 @@ sel_get_any_uid (const char *name)
return (SEL) l->head;
}
+SEL
+sel_getTypedSelector (const char *name)
+{
+ sidx i;
+
+ if (name == NULL)
+ return NULL;
+
+ objc_mutex_lock (__objc_runtime_mutex);
+
+ /* Look for a typed selector. */
+ i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name);
+ if (i != 0)
+ {
+ struct objc_list *l;
+
+ for (l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
+ l; l = l->tail)
+ {
+ SEL s = (SEL) l->head;
+ if (s->sel_types)
+ {
+ objc_mutex_unlock (__objc_runtime_mutex);
+ return s;
+ }
+ }
+ }
+
+ /* No typed selector found. Return NULL. */
+ objc_mutex_unlock (__objc_runtime_mutex);
+ return 0;
+}
+
+SEL *
+sel_copyTypedSelectorList (const char *name, unsigned int *numberOfReturnedSelectors)
+{
+ unsigned int count = 0;
+ SEL *returnValue = NULL;
+ sidx i;
+
+ if (name == NULL)
+ {
+ if (numberOfReturnedSelectors)
+ *numberOfReturnedSelectors = 0;
+ return NULL;
+ }
+
+ objc_mutex_lock (__objc_runtime_mutex);
+
+ /* Count how many selectors we have. */
+ i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name);
+ if (i != 0)
+ {
+ struct objc_list *selector_list = NULL;
+ selector_list = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
+
+ /* Count how many selectors we have. */
+ {
+ struct objc_list *l;
+ for (l = selector_list; l; l = l->tail)
+ count++;
+ }
+
+ if (count != 0)
+ {
+ /* Allocate enough memory to hold them. */
+ returnValue = (SEL *)(malloc (sizeof (SEL) * (count + 1)));
+
+ /* Copy the selectors. */
+ {
+ unsigned int j;
+ for (j = 0; j < count; j++)
+ {
+ returnValue[j] = (SEL)(selector_list->head);
+ selector_list = selector_list->tail;
+ }
+ returnValue[j] = NULL;
+ }
+ }
+ }
+
+ objc_mutex_unlock (__objc_runtime_mutex);
+
+ if (numberOfReturnedSelectors)
+ *numberOfReturnedSelectors = count;
+
+ return returnValue;
+}
+
/* Get the name of a selector. If the selector is unknown, the empty
string "" is returned. */
const char *sel_getName (SEL selector)
@@ -354,7 +477,7 @@ sel_is_mapped (SEL selector)
return ((idx > 0) && (idx <= __objc_selector_max_index));
}
-const char *sel_getType (SEL selector)
+const char *sel_getTypeEncoding (SEL selector)
{
if (selector)
return selector->sel_types;
@@ -365,7 +488,7 @@ const char *sel_getType (SEL selector)
/* Traditional GNU Objective-C Runtime API. */
const char *sel_get_type (SEL selector)
{
- return sel_getType (selector);
+ return sel_getTypeEncoding (selector);
}
/* The uninstalled dispatch table. */
@@ -403,11 +526,16 @@ pool_alloc_selector(void)
/* Store the passed selector name in the selector record and return
its selector value (value returned by sel_get_uid). Assume that
the calling function has locked down __objc_runtime_mutex. The
- is_const parameter tells us if the name and types parameters are
+ 'is_const' parameter tells us if the name and types parameters are
really constant or not. If YES then they are constant and we can
just store the pointers. If NO then we need to copy name and types
- because the pointers may disappear later on. */
-SEL
+ because the pointers may disappear later on. If the 'orig'
+ parameter is not NULL, then we are registering a selector from a
+ module, and 'orig' is that selector. In this case, we can put the
+ selector in the tables if needed, and orig->sel_id is updated with
+ the selector ID of the registered selector, and 'orig' is
+ returned. */
+static SEL
__sel_register_typed_name (const char *name, const char *types,
struct objc_selector *orig, BOOL is_const)
{
@@ -418,17 +546,19 @@ __sel_register_typed_name (const char *name, const char *types,
i = (sidx) objc_hash_value_for_key (__objc_selector_hash, name);
if (soffset_decode (i) != 0)
{
- for (l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
+ /* There are already selectors with that name. Examine them to
+ see if the one we're registering already exists. */
+ for (l = (struct objc_list *)sarray_get_safe (__objc_selector_array, i);
l; l = l->tail)
{
- SEL s = (SEL) l->head;
+ SEL s = (SEL)l->head;
if (types == 0 || s->sel_types == 0)
{
if (s->sel_types == types)
{
if (orig)
{
- orig->sel_id = (void *) i;
+ orig->sel_id = (void *)i;
return orig;
}
else
@@ -439,85 +569,102 @@ __sel_register_typed_name (const char *name, const char *types,
{
if (orig)
{
- orig->sel_id = (void *) i;
+ orig->sel_id = (void *)i;
return orig;
}
else
return s;
}
}
+ /* A selector with this specific name/type combination does not
+ exist yet. We need to register it. */
if (orig)
j = orig;
else
j = pool_alloc_selector ();
- j->sel_id = (void *) i;
- /* Can we use the pointer or must copy types? Don't copy if
+ j->sel_id = (void *)i;
+ /* Can we use the pointer or must we copy types ? Don't copy if
NULL. */
if ((is_const) || (types == 0))
- j->sel_types = (const char *) types;
+ j->sel_types = types;
else
{
- j->sel_types = (char *) objc_malloc (strlen (types) + 1);
- strcpy ((char *) j->sel_types, types);
+ j->sel_types = (char *)objc_malloc (strlen (types) + 1);
+ strcpy ((char *)j->sel_types, types);
}
- l = (struct objc_list *) sarray_get_safe (__objc_selector_array, i);
+ l = (struct objc_list *)sarray_get_safe (__objc_selector_array, i);
}
else
{
+ /* There are no other selectors with this name registered in the
+ runtime tables. */
+ const char *new_name;
+
+ /* Determine i. */
__objc_selector_max_index += 1;
i = soffset_encode (__objc_selector_max_index);
+
+ /* Prepare the selector. */
if (orig)
j = orig;
else
j = pool_alloc_selector ();
- j->sel_id = (void *) i;
- /* Can we use the pointer or must copy types? Don't copy if
+ j->sel_id = (void *)i;
+ /* Can we use the pointer or must we copy types ? Don't copy if
NULL. */
- if ((is_const) || (types == 0))
- j->sel_types = (const char *) types;
+ if (is_const || (types == 0))
+ j->sel_types = types;
+ else
+ {
+ j->sel_types = (char *)objc_malloc (strlen (types) + 1);
+ strcpy ((char *)j->sel_types, types);
+ }
+
+ /* Since this is the first selector with this name, we need to
+ register the correspondence between 'i' (the sel_id) and
+ 'name' (the actual string) in __objc_selector_names and
+ __objc_selector_hash. */
+
+ /* Can we use the pointer or must we copy name ? Don't copy if
+ NULL. (FIXME: Can the name really be NULL here ?) */
+ if (is_const || (name == 0))
+ new_name = name;
else
{
- j->sel_types = (char *) objc_malloc (strlen (types) + 1);
- strcpy ((char *) j->sel_types, types);
+ new_name = (char *)objc_malloc (strlen (name) + 1);
+ strcpy ((char *)new_name, name);
}
+
+ /* This maps the sel_id to the name. */
+ sarray_at_put_safe (__objc_selector_names, i, (void *)new_name);
+
+ /* This maps the name to the sel_id. */
+ objc_hash_add (&__objc_selector_hash, (void *)new_name, (void *)i);
+
l = 0;
}
DEBUG_PRINTF ("Record selector %s[%s] as: %ld\n", name, types,
- (long) soffset_decode (i));
-
- {
- int is_new = (l == 0);
- const char *new_name;
-
- /* Can we use the pointer or must copy name? Don't copy if
- NULL. */
- if ((is_const) || (name == 0))
- new_name = name;
- else
- {
- new_name = (char *) objc_malloc (strlen (name) + 1);
- strcpy ((char *) new_name, name);
- }
-
- l = list_cons ((void *) j, l);
- sarray_at_put_safe (__objc_selector_names, i, (void *) new_name);
- sarray_at_put_safe (__objc_selector_array, i, (void *) l);
- if (is_new)
- objc_hash_add (&__objc_selector_hash, (void *) new_name, (void *) i);
- }
-
+ (long)soffset_decode (i));
+
+ /* Now add the selector to the list of selectors with that id. */
+ l = list_cons ((void *)j, l);
+ sarray_at_put_safe (__objc_selector_array, i, (void *)l);
+
sarray_realloc (__objc_uninstalled_dtable, __objc_selector_max_index + 1);
- return (SEL) j;
+ return (SEL)j;
}
SEL
sel_registerName (const char *name)
{
SEL ret;
+
+ if (name == NULL)
+ return NULL;
objc_mutex_lock (__objc_runtime_mutex);
/* Assume that name is not constant static memory and needs to be
@@ -540,6 +687,9 @@ sel_registerTypedName (const char *name, const char *type)
{
SEL ret;
+ if (name == NULL)
+ return NULL;
+
objc_mutex_lock (__objc_runtime_mutex);
/* Assume that name and type are not constant static memory and need
to be copied before put into a runtime structure. is_const ==
diff --git a/libobjc/sendmsg.c b/libobjc/sendmsg.c
index 5192d161973..0cb375db39b 100644
--- a/libobjc/sendmsg.c
+++ b/libobjc/sendmsg.c
@@ -23,6 +23,9 @@ a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */
+/* Uncommented the following line to enable debug logging. Use this
+ only while debugging the runtime. */
+/* #define DEBUG 1 */
/* FIXME: This file has no business including tm.h. */
/* FIXME: This should be using libffi instead of __builtin_apply
@@ -543,6 +546,7 @@ __objc_send_initialize (Class class)
if (! CLS_ISINITIALIZED (class))
{
+ DEBUG_PRINTF ("+initialize: need to initialize class '%s'\n", class->name);
CLS_SETINITIALIZED (class);
CLS_SETINITIALIZED (class->class_pointer);
@@ -579,7 +583,17 @@ __objc_send_initialize (Class class)
method_list = method_list->method_next;
}
if (imp)
- (*imp) ((id) class, op);
+ {
+ DEBUG_PRINTF (" begin of [%s +initialize]\n", class->name);
+ (*imp) ((id) class, op);
+ DEBUG_PRINTF (" end of [%s +initialize]\n", class->name);
+ }
+#ifdef DEBUG
+ else
+ {
+ DEBUG_PRINTF (" class '%s' has no +initialize method\n", class->name);
+ }
+#endif
}
}
}
@@ -621,6 +635,8 @@ __objc_install_dispatch_table_for_class (Class class)
re-compute all class links. */
if (! CLS_ISRESOLV (class))
__objc_resolve_class_links ();
+
+ DEBUG_PRINTF ("__objc_install_dispatch_table_for_class (%s)\n", class->name);
super = class->super_class;
@@ -650,6 +666,8 @@ __objc_update_dispatch_table_for_class (Class class)
if (class->dtable == __objc_uninstalled_dtable)
return;
+ DEBUG_PRINTF (" _objc_update_dispatch_table_for_class (%s)\n", class->name);
+
objc_mutex_lock (__objc_runtime_mutex);
arr = class->dtable;
@@ -759,6 +777,45 @@ class_addMethod (Class class_, SEL selector, IMP implementation,
if (method_name == NULL)
return NO;
+ /* If the method already exists in the class, return NO. It is fine
+ if the method already exists in the superclass; in that case, we
+ are overriding it. */
+ if (CLS_IS_IN_CONSTRUCTION (class_))
+ {
+ /* The class only contains a list of methods; they have not been
+ registered yet, ie, the method_name of each of them is still
+ a string, not a selector. Iterate manually over them to
+ check if we have already added the method. */
+ struct objc_method_list * method_list = class_->methods;
+ while (method_list)
+ {
+ int i;
+
+ /* Search the method list. */
+ for (i = 0; i < method_list->method_count; ++i)
+ {
+ struct objc_method * method = &method_list->method_list[i];
+
+ if (method->method_name
+ && strcmp ((char *)method->method_name, method_name) == 0)
+ return NO;
+ }
+
+ /* The method wasn't found. Follow the link to the next list of
+ methods. */
+ method_list = method_list->method_next;
+ }
+ /* The method wasn't found. It's a new one. Go ahead and add
+ it. */
+ }
+ else
+ {
+ /* Do the standard lookup. This assumes the selectors are
+ mapped. */
+ if (search_for_method_in_list (class_->methods, selector))
+ return NO;
+ }
+
method_list = (struct objc_method_list *)objc_calloc (1, sizeof (struct objc_method_list));
method_list->method_count = 1;