Commit 575584a9 by Nicola Pero Committed by Nicola Pero

In libobjc/: 2010-12-18 Nicola Pero <nicola.pero@meta-innovation.com>

In libobjc/:
2010-12-18  Nicola Pero  <nicola.pero@meta-innovation.com>

	* class.c: Tidied up comments and indentation.  No code changes.
	* error.c: Same.
	* exception.c: Same.
	* init.c: Same.
	* ivars.c: Same.
	* memory.c: Same.
	* objc-foreach.c: Same.
	* objc-sync.c: Same.
	* objects.c: Same.
	* protocols.c: Same.
	* sarray.c: Same.
	* thr.c: Same.

From-SVN: r168022
parent f21fe684
2010-12-18 Nicola Pero <nicola.pero@meta-innovation.com>
* class.c: Tidied up comments and indentation. No code changes.
* error.c: Same.
* exception.c: Same.
* init.c: Same.
* ivars.c: Same.
* memory.c: Same.
* objc-foreach.c: Same.
* objc-sync.c: Same.
* objects.c: Same.
* protocols.c: Same.
* sarray.c: Same.
* thr.c: Same.
2010-12-17 Nicola Pero <nicola.pero@meta-innovation.com> 2010-12-17 Nicola Pero <nicola.pero@meta-innovation.com>
* init.c: Include objc/runtime.h and objc-private/module-abi-8.h * init.c: Include objc/runtime.h and objc-private/module-abi-8.h
......
...@@ -26,12 +26,10 @@ a copy of the GCC Runtime Library Exception along with this program; ...@@ -26,12 +26,10 @@ a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */ <http://www.gnu.org/licenses/>. */
/* /* The code in this file critically affects class method invocation
The code in this file critically affects class method invocation
speed. This long preamble comment explains why, and the issues speed. This long preamble comment explains why, and the issues
involved. involved.
One of the traditional weaknesses of the GNU Objective-C runtime is One of the traditional weaknesses of the GNU Objective-C runtime is
that class method invocations are slow. The reason is that when you that class method invocations are slow. The reason is that when you
write write
...@@ -97,11 +95,11 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see ...@@ -97,11 +95,11 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#include <string.h> /* For memset */ #include <string.h> /* For memset */
/* We use a table which maps a class name to the corresponding class /* We use a table which maps a class name to the corresponding class
* pointer. The first part of this file defines this table, and pointer. The first part of this file defines this table, and
* functions to do basic operations on the table. The second part of functions to do basic operations on the table. The second part of
* the file implements some higher level Objective-C functionality for the file implements some higher level Objective-C functionality for
* classes by using the functions provided in the first part to manage classes by using the functions provided in the first part to manage
* the table. */ the table. */
/** /**
** Class Table Internals ** Class Table Internals
...@@ -176,7 +174,8 @@ class_table_setup (void) ...@@ -176,7 +174,8 @@ class_table_setup (void)
} }
/* Insert a class in the table (used when a new class is registered). */ /* Insert a class in the table (used when a new class is
registered). */
static void static void
class_table_insert (const char *class_name, Class class_pointer) class_table_insert (const char *class_name, Class class_pointer)
{ {
...@@ -221,18 +220,15 @@ class_table_replace (Class old_class_pointer, Class new_class_pointer) ...@@ -221,18 +220,15 @@ class_table_replace (Class old_class_pointer, Class new_class_pointer)
{ {
hash++; hash++;
if (hash < CLASS_TABLE_SIZE) if (hash < CLASS_TABLE_SIZE)
{
node = class_table_array[hash]; node = class_table_array[hash];
} }
}
else else
{ {
Class class1 = node->pointer; Class class1 = node->pointer;
if (class1 == old_class_pointer) if (class1 == old_class_pointer)
{
node->pointer = new_class_pointer; node->pointer = new_class_pointer;
}
node = node->next; node = node->next;
} }
} }
...@@ -267,10 +263,8 @@ class_table_get_safe (const char *class_name) ...@@ -267,10 +263,8 @@ class_table_get_safe (const char *class_name)
for (i = 0; i < length; i++) for (i = 0; i < length; i++)
{ {
if ((node->name)[i] != class_name[i]) if ((node->name)[i] != class_name[i])
{
break; break;
} }
}
if (i == length) if (i == length)
{ {
...@@ -309,9 +303,7 @@ class_table_next (struct class_table_enumerator **e) ...@@ -309,9 +303,7 @@ class_table_next (struct class_table_enumerator **e)
next = class_table_array[enumerator->hash]; next = class_table_array[enumerator->hash];
} }
else else
{
next = enumerator->node->next; next = enumerator->node->next;
}
if (next != NULL) if (next != NULL)
{ {
...@@ -385,18 +377,16 @@ class_table_print_histogram (void) ...@@ -385,18 +377,16 @@ class_table_print_histogram (void)
{ {
printf ("%4d:", i + 1); printf ("%4d:", i + 1);
for (j = 0; j < counter; j++) for (j = 0; j < counter; j++)
{
printf ("X"); printf ("X");
}
printf ("\n"); printf ("\n");
counter = 0; counter = 0;
} }
} }
printf ("%4d:", i + 1); printf ("%4d:", i + 1);
for (j = 0; j < counter; j++) for (j = 0; j < counter; j++)
{
printf ("X"); printf ("X");
}
printf ("\n"); printf ("\n");
} }
#endif /* DEBUGGING FUNCTIONS */ #endif /* DEBUGGING FUNCTIONS */
...@@ -558,10 +548,8 @@ objc_getClassList (Class *returnValue, int maxNumberOfClassesToReturn) ...@@ -558,10 +548,8 @@ objc_getClassList (Class *returnValue, int maxNumberOfClassesToReturn)
if (count < maxNumberOfClassesToReturn) if (count < maxNumberOfClassesToReturn)
returnValue[count] = node->pointer; returnValue[count] = node->pointer;
else else
{
return count; return count;
} }
}
count++; count++;
node = node->next; node = node->next;
} }
...@@ -869,22 +857,18 @@ __objc_update_classes_with_methods (struct objc_method *method_a, struct objc_me ...@@ -869,22 +857,18 @@ __objc_update_classes_with_methods (struct objc_method *method_a, struct objc_me
/* If the method is one of the ones we are looking /* If the method is one of the ones we are looking
for, update the implementation. */ for, update the implementation. */
if (method == method_a) if (method == method_a)
{
sarray_at_put_safe (class->dtable, sarray_at_put_safe (class->dtable,
(sidx) method_a->method_name->sel_id, (sidx) method_a->method_name->sel_id,
method_a->method_imp); method_a->method_imp);
}
if (method == method_b) if (method == method_b)
{ {
if (method_b != NULL) if (method_b != NULL)
{
sarray_at_put_safe (class->dtable, sarray_at_put_safe (class->dtable,
(sidx) method_b->method_name->sel_id, (sidx) method_b->method_name->sel_id,
method_b->method_imp); method_b->method_imp);
} }
} }
}
method_list = method_list->method_next; method_list = method_list->method_next;
} }
......
...@@ -28,8 +28,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see ...@@ -28,8 +28,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
/* __USE_FIXED_PROTOTYPES__ used to be required to get prototypes for /* __USE_FIXED_PROTOTYPES__ used to be required to get prototypes for
malloc, free, etc. on some platforms. It is unclear if we still malloc, free, etc. on some platforms. It is unclear if we still
need it, but it can't hurt. need it, but it can't hurt. */
*/
#define __USE_FIXED_PROTOTYPES__ #define __USE_FIXED_PROTOTYPES__
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
......
...@@ -33,15 +33,13 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see ...@@ -33,15 +33,13 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
/* This hook allows libraries to sepecify special actions when an /* This hook allows libraries to sepecify special actions when an
exception is thrown without a handler in place. This is deprecated exception is thrown without a handler in place. This is deprecated
in favour of objc_set_uncaught_exception_handler (). in favour of objc_set_uncaught_exception_handler (). */
*/
void (*_objc_unexpected_exception) (id exception); /* !T:SAFE */ void (*_objc_unexpected_exception) (id exception); /* !T:SAFE */
/* 'is_kind_of_exception_matcher' is our default exception matcher - /* 'is_kind_of_exception_matcher' is our default exception matcher -
it determines if the object 'exception' is of class 'catch_class', it determines if the object 'exception' is of class 'catch_class',
or of a subclass. or of a subclass. */
*/
static int static int
is_kind_of_exception_matcher (Class catch_class, id exception) is_kind_of_exception_matcher (Class catch_class, id exception)
{ {
...@@ -49,9 +47,8 @@ is_kind_of_exception_matcher (Class catch_class, id exception) ...@@ -49,9 +47,8 @@ is_kind_of_exception_matcher (Class catch_class, id exception)
if (catch_class == Nil) if (catch_class == Nil)
return 1; return 1;
/* If exception is nil (eg, @throw nil;), then it can only be catched /* If exception is nil (eg, @throw nil;), then it can only be
* by a catch-all (eg, @catch (id object)). catched by a catch-all (eg, @catch (id object)). */
*/
if (exception != nil) if (exception != nil)
{ {
Class c; Class c;
...@@ -114,19 +111,18 @@ static const _Unwind_Exception_Class __objc_exception_class ...@@ -114,19 +111,18 @@ static const _Unwind_Exception_Class __objc_exception_class
/* This is the object that is passed around by the Objective C runtime /* This is the object that is passed around by the Objective C runtime
to represent the exception in flight. */ to represent the exception in flight. */
struct ObjcException struct ObjcException
{ {
/* This bit is needed in order to interact with the unwind runtime. */ /* This bit is needed in order to interact with the unwind runtime. */
struct _Unwind_Exception base; struct _Unwind_Exception base;
/* The actual object we want to throw. Note: must come immediately after /* The actual object we want to throw. Note: must come immediately
unwind header. */ after unwind header. */
id value; id value;
#ifdef __ARM_EABI_UNWINDER__ #ifdef __ARM_EABI_UNWINDER__
/* Note: we use the barrier cache defined in the unwind control block for /* Note: we use the barrier cache defined in the unwind control
ARM EABI. */ block for ARM EABI. */
#else #else
/* Cache some internal unwind data between phase 1 and phase 2. */ /* Cache some internal unwind data between phase 1 and phase 2. */
_Unwind_Ptr landingPad; _Unwind_Ptr landingPad;
...@@ -156,14 +152,16 @@ parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p, ...@@ -156,14 +152,16 @@ parse_lsda_header (struct _Unwind_Context *context, const unsigned char *p,
info->Start = (context ? _Unwind_GetRegionStart (context) : 0); info->Start = (context ? _Unwind_GetRegionStart (context) : 0);
/* Find @LPStart, the base to which landing pad offsets are relative. */ /* Find @LPStart, the base to which landing pad offsets are
relative. */
lpstart_encoding = *p++; lpstart_encoding = *p++;
if (lpstart_encoding != DW_EH_PE_omit) if (lpstart_encoding != DW_EH_PE_omit)
p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart); p = read_encoded_value (context, lpstart_encoding, p, &info->LPStart);
else else
info->LPStart = info->Start; info->LPStart = info->Start;
/* Find @TType, the base of the handler and exception spec type data. */ /* Find @TType, the base of the handler and exception spec type
data. */
info->ttype_encoding = *p++; info->ttype_encoding = *p++;
if (info->ttype_encoding != DW_EH_PE_omit) if (info->ttype_encoding != DW_EH_PE_omit)
{ {
...@@ -222,7 +220,8 @@ get_ttype_entry (struct lsda_header_info *info, _Unwind_Word i) ...@@ -222,7 +220,8 @@ get_ttype_entry (struct lsda_header_info *info, _Unwind_Word i)
#endif #endif
/* Using a different personality function name causes link failures /* Using a different personality function name causes link failures
when trying to mix code using different exception handling models. */ when trying to mix code using different exception handling
models. */
#ifdef SJLJ_EXCEPTIONS #ifdef SJLJ_EXCEPTIONS
#define PERSONALITY_FUNCTION __gnu_objc_personality_sj0 #define PERSONALITY_FUNCTION __gnu_objc_personality_sj0
#define __builtin_eh_return_data_regno(x) x #define __builtin_eh_return_data_regno(x) x
...@@ -294,14 +293,14 @@ PERSONALITY_FUNCTION (int version, ...@@ -294,14 +293,14 @@ PERSONALITY_FUNCTION (int version,
} }
actions |= state & _US_FORCE_UNWIND; actions |= state & _US_FORCE_UNWIND;
/* TODO: Foreign exceptions need some attention (e.g. rethrowing doesn't /* TODO: Foreign exceptions need some attention (e.g. rethrowing
work). */ doesn't work). */
foreign_exception = 0; foreign_exception = 0;
/* The dwarf unwinder assumes the context structure holds things like the /* The dwarf unwinder assumes the context structure holds things
function and LSDA pointers. The ARM implementation caches these in like the function and LSDA pointers. The ARM implementation
the exception header (UCB). To avoid rewriting everything we make the caches these in the exception header (UCB). To avoid rewriting
virtual IP register point at the UCB. */ everything we make the virtual IP register point at the UCB. */
ip = (_Unwind_Ptr) ue_header; ip = (_Unwind_Ptr) ue_header;
_Unwind_SetGR (context, 12, ip); _Unwind_SetGR (context, 12, ip);
...@@ -351,8 +350,8 @@ PERSONALITY_FUNCTION (int version, ...@@ -351,8 +350,8 @@ PERSONALITY_FUNCTION (int version,
#ifdef SJLJ_EXCEPTIONS #ifdef SJLJ_EXCEPTIONS
/* The given "IP" is an index into the call-site table, with two /* The given "IP" is an index into the call-site table, with two
exceptions -- -1 means no-action, and 0 means terminate. But exceptions -- -1 means no-action, and 0 means terminate. But
since we're using uleb128 values, we've not got random access since we're using uleb128 values, we've not got random access to
to the array. */ the array. */
if ((int) ip < 0) if ((int) ip < 0)
return _URC_CONTINUE_UNWIND; return _URC_CONTINUE_UNWIND;
else else
...@@ -373,13 +372,15 @@ PERSONALITY_FUNCTION (int version, ...@@ -373,13 +372,15 @@ PERSONALITY_FUNCTION (int version,
goto found_something; goto found_something;
} }
#else #else
/* Search the call-site table for the action associated with this IP. */ /* Search the call-site table for the action associated with this
IP. */
while (p < info.action_table) while (p < info.action_table)
{ {
_Unwind_Ptr cs_start, cs_len, cs_lp; _Unwind_Ptr cs_start, cs_len, cs_lp;
_uleb128_t cs_action; _uleb128_t cs_action;
/* Note that all call-site encodings are "absolute" displacements. */ /* Note that all call-site encodings are "absolute"
displacements. */
p = read_encoded_value (0, info.call_site_encoding, p, &cs_start); p = read_encoded_value (0, info.call_site_encoding, p, &cs_start);
p = read_encoded_value (0, info.call_site_encoding, p, &cs_len); p = read_encoded_value (0, info.call_site_encoding, p, &cs_len);
p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp); p = read_encoded_value (0, info.call_site_encoding, p, &cs_lp);
...@@ -400,8 +401,8 @@ PERSONALITY_FUNCTION (int version, ...@@ -400,8 +401,8 @@ PERSONALITY_FUNCTION (int version,
#endif /* SJLJ_EXCEPTIONS */ #endif /* SJLJ_EXCEPTIONS */
/* If ip is not present in the table, C++ would call terminate. */ /* If ip is not present in the table, C++ would call terminate. */
/* ??? As with Java, it's perhaps better to tweek the LSDA to /* ??? As with Java, it's perhaps better to tweek the LSDA to that
that no-action is mapped to no-entry. */ no-action is mapped to no-entry. */
CONTINUE_UNWINDING; CONTINUE_UNWINDING;
found_something: found_something:
...@@ -410,8 +411,8 @@ PERSONALITY_FUNCTION (int version, ...@@ -410,8 +411,8 @@ PERSONALITY_FUNCTION (int version,
if (landing_pad == 0) if (landing_pad == 0)
{ {
/* If ip is present, and has a null landing pad, there are /* If ip is present, and has a null landing pad, there are no
no cleanups or handlers to be run. */ cleanups or handlers to be run. */
} }
else if (action_record == 0) else if (action_record == 0)
{ {
...@@ -438,14 +439,14 @@ PERSONALITY_FUNCTION (int version, ...@@ -438,14 +439,14 @@ PERSONALITY_FUNCTION (int version,
} }
/* During forced unwinding, we only run cleanups. With a /* During forced unwinding, we only run cleanups. With a
foreign exception class, we have no class info to match. */ foreign exception class, we have no class info to
match. */
else if ((actions & _UA_FORCE_UNWIND) || foreign_exception) else if ((actions & _UA_FORCE_UNWIND) || foreign_exception)
; ;
else if (ar_filter > 0) else if (ar_filter > 0)
{ {
/* Positive filter values are handlers. */ /* Positive filter values are handlers. */
Class catch_type = get_ttype_entry (&info, ar_filter); Class catch_type = get_ttype_entry (&info, ar_filter);
if ((*__objc_exception_matcher) (catch_type, xh->value)) if ((*__objc_exception_matcher) (catch_type, xh->value))
...@@ -476,7 +477,8 @@ PERSONALITY_FUNCTION (int version, ...@@ -476,7 +477,8 @@ PERSONALITY_FUNCTION (int version,
if (!saw_handler) if (!saw_handler)
CONTINUE_UNWINDING; CONTINUE_UNWINDING;
/* For domestic exceptions, we cache data from phase 1 for phase 2. */ /* For domestic exceptions, we cache data from phase 1 for phase
2. */
if (!foreign_exception) if (!foreign_exception)
{ {
#ifdef __ARM_EABI_UNWINDER__ #ifdef __ARM_EABI_UNWINDER__
...@@ -531,16 +533,14 @@ objc_exception_throw (id exception) ...@@ -531,16 +533,14 @@ objc_exception_throw (id exception)
#endif #endif
/* No exception handler was installed. Call the uncaught exception /* No exception handler was installed. Call the uncaught exception
handler if any is defined. handler if any is defined. */
*/
if (__objc_uncaught_exception_handler != 0) if (__objc_uncaught_exception_handler != 0)
{ {
(*__objc_uncaught_exception_handler) (exception); (*__objc_uncaught_exception_handler) (exception);
} }
/* As a last resort support the old, deprecated way of setting an /* As a last resort support the old, deprecated way of setting an
uncaught exception handler. uncaught exception handler. */
*/
if (_objc_unexpected_exception != 0) if (_objc_unexpected_exception != 0)
{ {
(*_objc_unexpected_exception) (exception); (*_objc_unexpected_exception) (exception);
......
...@@ -47,11 +47,9 @@ class_getInstanceVariable (Class class_, const char *name) ...@@ -47,11 +47,9 @@ class_getInstanceVariable (Class class_, const char *name)
struct objc_ivar *ivar = &(ivars->ivar_list[i]); struct objc_ivar *ivar = &(ivars->ivar_list[i]);
if (!strcmp (ivar->ivar_name, name)) if (!strcmp (ivar->ivar_name, name))
{
return ivar; return ivar;
} }
} }
}
class_ = class_getSuperclass (class_); class_ = class_getSuperclass (class_);
} }
} }
...@@ -83,10 +81,8 @@ object_getIndexedIvars (id object) ...@@ -83,10 +81,8 @@ object_getIndexedIvars (id object)
if (object == nil) if (object == nil)
return NULL; return NULL;
else else
{
return (void *)(((char *)object) return (void *)(((char *)object)
+ object->class_pointer->instance_size); + object->class_pointer->instance_size);
}
} }
struct objc_ivar * struct objc_ivar *
...@@ -203,9 +199,7 @@ struct objc_ivar ** class_copyIvarList (Class class_, unsigned int *numberOfRetu ...@@ -203,9 +199,7 @@ struct objc_ivar ** class_copyIvarList (Class class_, unsigned int *numberOfRetu
/* Copy the ivars. */ /* Copy the ivars. */
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
{
returnValue[i] = &(ivar_list->ivar_list[i]); returnValue[i] = &(ivar_list->ivar_list[i]);
}
returnValue[i] = NULL; returnValue[i] = NULL;
} }
...@@ -243,11 +237,9 @@ class_addIvar (Class class_, const char * ivar_name, size_t size, ...@@ -243,11 +237,9 @@ class_addIvar (Class class_, const char * ivar_name, size_t size,
struct objc_ivar *ivar = &(ivars->ivar_list[i]); struct objc_ivar *ivar = &(ivars->ivar_list[i]);
if (strcmp (ivar->ivar_name, ivar_name) == 0) if (strcmp (ivar->ivar_name, ivar_name) == 0)
{
return NO; return NO;
} }
} }
}
/* Ok, no direct ivars. Check superclasses. */ /* Ok, no direct ivars. Check superclasses. */
if (class_getInstanceVariable (objc_getClass ((char *)(class_->super_class)), if (class_getInstanceVariable (objc_getClass ((char *)(class_->super_class)),
......
...@@ -24,11 +24,9 @@ a copy of the GCC Runtime Library Exception along with this program; ...@@ -24,11 +24,9 @@ a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */ <http://www.gnu.org/licenses/>. */
/* /* This file includes the standard functions for memory allocation and
This file includes the standard functions for memory allocation and
disposal. Users should use these functions in their ObjC programs disposal. Users should use these functions in their ObjC programs
so that they work properly with garbage collectors. so that they work properly with garbage collectors. */
*/
/* TODO: Turn these into macros or inline functions. */ /* TODO: Turn these into macros or inline functions. */
...@@ -37,8 +35,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see ...@@ -37,8 +35,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
/* __USE_FIXED_PROTOTYPES__ used to be required to get prototypes for /* __USE_FIXED_PROTOTYPES__ used to be required to get prototypes for
malloc, free, etc. on some platforms. It is unclear if we still malloc, free, etc. on some platforms. It is unclear if we still
need it, but it can't hurt. need it, but it can't hurt. */
*/
#define __USE_FIXED_PROTOTYPES__ #define __USE_FIXED_PROTOTYPES__
#include <stdlib.h> #include <stdlib.h>
...@@ -163,11 +160,8 @@ objc_valloc (size_t size) ...@@ -163,11 +160,8 @@ objc_valloc (size_t size)
#endif /* !OBJC_WITH_GC */ #endif /* !OBJC_WITH_GC */
/* /* Hook functions for memory allocation and disposal. Deprecated and
Hook functions for memory allocation and disposal. Deprecated currently unused. */
and currently unused.
*/
void *(*_objc_malloc) (size_t) = malloc; void *(*_objc_malloc) (size_t) = malloc;
void *(*_objc_atomic_malloc) (size_t) = malloc; void *(*_objc_atomic_malloc) (size_t) = malloc;
void *(*_objc_valloc) (size_t) = malloc; void *(*_objc_valloc) (size_t) = malloc;
......
...@@ -22,11 +22,9 @@ a copy of the GCC Runtime Library Exception along with this program; ...@@ -22,11 +22,9 @@ a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */ <http://www.gnu.org/licenses/>. */
/* /* This file implements objc_enumeration_mutation() and
This file implements objc_enumeration_mutation() and
objc_set_enumeration_mutation_handler(), the two functions required objc_set_enumeration_mutation_handler(), the two functions required
to handle mutations during a fast enumeration. to handle mutations during a fast enumeration. */
*/
#include "objc-private/common.h" #include "objc-private/common.h"
#include "objc-private/error.h" /* For _objc_abort() */ #include "objc-private/error.h" /* For _objc_abort() */
#include "objc/runtime.h" /* For objc_enumerationMutation() and objc_set_enumeration_mutation_handler() */ #include "objc/runtime.h" /* For objc_enumerationMutation() and objc_set_enumeration_mutation_handler() */
......
...@@ -22,16 +22,14 @@ a copy of the GCC Runtime Library Exception along with this program; ...@@ -22,16 +22,14 @@ a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */ <http://www.gnu.org/licenses/>. */
/* /* This file implements objc_sync_enter() and objc_sync_exit(), the
This file implements objc_sync_enter() and objc_sync_exit(), the
two functions required to support @synchronized(). two functions required to support @synchronized().
objc_sync_enter(object) needs to get a recursive lock associated objc_sync_enter(object) needs to get a recursive lock associated
with 'object', and lock it. with 'object', and lock it.
objc_sync_exit(object) needs to get the recursive lock associated objc_sync_exit(object) needs to get the recursive lock associated
with 'object', and unlock it. with 'object', and unlock it. */
*/
/* To avoid the overhead of continuously allocating and deallocating /* To avoid the overhead of continuously allocating and deallocating
locks, we implement a pool of locks. When a lock is needed for an locks, we implement a pool of locks. When a lock is needed for an
...@@ -61,18 +59,15 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see ...@@ -61,18 +59,15 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
which is already held by the current thread without having to use which is already held by the current thread without having to use
any protection lock or synchronization mechanism. It can so detect any protection lock or synchronization mechanism. It can so detect
recursive locks/unlocks, and transform them into no-ops that recursive locks/unlocks, and transform them into no-ops that
require no actual locking or synchronization mechanisms at all. require no actual locking or synchronization mechanisms at all. */
*/
/* You can disable the thread-local cache (most likely to benchmark /* You can disable the thread-local cache (most likely to benchmark
the code with and without it) by compiling with the code with and without it) by compiling with
-DSYNC_CACHE_DISABLE, or commenting out the following line. -DSYNC_CACHE_DISABLE, or commenting out the following line. */
*/
/* #define SYNC_CACHE_DISABLE */ /* #define SYNC_CACHE_DISABLE */
/* If thread-local storage is not available, automatically disable the /* If thread-local storage is not available, automatically disable the
cache. cache. */
*/
#ifndef HAVE_TLS #ifndef HAVE_TLS
# define SYNC_CACHE_DISABLE # define SYNC_CACHE_DISABLE
#endif #endif
...@@ -85,13 +80,11 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see ...@@ -85,13 +80,11 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
/* We have 32 pools of locks, each of them protected by its own /* We have 32 pools of locks, each of them protected by its own
protection lock. It's tempting to increase this number to reduce protection lock. It's tempting to increase this number to reduce
contention; but in our tests it is high enough. contention; but in our tests it is high enough. */
*/
#define SYNC_NUMBER_OF_POOLS 32 #define SYNC_NUMBER_OF_POOLS 32
/* Given an object, it determines which pool contains the associated /* Given an object, it determines which pool contains the associated
lock. lock. */
*/
#define SYNC_OBJECT_HASH(OBJECT) ((((size_t)OBJECT >> 8) ^ (size_t)OBJECT) & (SYNC_NUMBER_OF_POOLS - 1)) #define SYNC_OBJECT_HASH(OBJECT) ((((size_t)OBJECT >> 8) ^ (size_t)OBJECT) & (SYNC_NUMBER_OF_POOLS - 1))
/* The locks protecting each pool. */ /* The locks protecting each pool. */
...@@ -126,8 +119,8 @@ typedef struct lock_node ...@@ -126,8 +119,8 @@ typedef struct lock_node
because in that case you know that node->usage_count can't get to because in that case you know that node->usage_count can't get to
zero until you release the lock. It is valid to have usage_count zero until you release the lock. It is valid to have usage_count
== 0 and object != nil; in that case, the lock is not currently == 0 and object != nil; in that case, the lock is not currently
being used, but is still currently associated with the object. being used, but is still currently associated with the
*/ object. */
id object; id object;
/* This is a counter reserved for use by the thread currently /* This is a counter reserved for use by the thread currently
...@@ -143,21 +136,18 @@ typedef struct lock_node ...@@ -143,21 +136,18 @@ typedef struct lock_node
require any synchronization with other threads, since it's require any synchronization with other threads, since it's
protected by the node->lock itself) instead of the usage_count protected by the node->lock itself) instead of the usage_count
(which requires locking the pool protection lock). And it can (which requires locking the pool protection lock). And it can
skip the call to objc_mutex_lock/unlock too. skip the call to objc_mutex_lock/unlock too. */
*/
unsigned int recursive_usage_count; unsigned int recursive_usage_count;
} *lock_node_ptr; } *lock_node_ptr;
/* The pools of locks. Each of them is a linked list of lock_nodes. /* The pools of locks. Each of them is a linked list of lock_nodes.
In the list we keep both unlocked and locked nodes. In the list we keep both unlocked and locked nodes. */
*/
static lock_node_ptr sync_pool_array[SYNC_NUMBER_OF_POOLS]; static lock_node_ptr sync_pool_array[SYNC_NUMBER_OF_POOLS];
#ifndef SYNC_CACHE_DISABLE #ifndef SYNC_CACHE_DISABLE
/* We store a cache of locks acquired by each thread in thread-local /* We store a cache of locks acquired by each thread in thread-local
storage. storage. */
*/
static __thread lock_node_ptr *lock_cache = NULL; static __thread lock_node_ptr *lock_cache = NULL;
/* This is a conservative implementation that uses a static array of /* This is a conservative implementation that uses a static array of
...@@ -176,8 +166,7 @@ static __thread lock_node_ptr *lock_cache = NULL; ...@@ -176,8 +166,7 @@ static __thread lock_node_ptr *lock_cache = NULL;
first 8 get the speed benefits of the cache, but the cache remains first 8 get the speed benefits of the cache, but the cache remains
always small, fast and predictable. always small, fast and predictable.
SYNC_CACHE_SIZE is the size of the lock cache for each thread. SYNC_CACHE_SIZE is the size of the lock cache for each thread. */
*/
#define SYNC_CACHE_SIZE 8 #define SYNC_CACHE_SIZE 8
#endif /* SYNC_CACHE_DISABLE */ #endif /* SYNC_CACHE_DISABLE */
...@@ -217,23 +206,20 @@ objc_sync_enter (id object) ...@@ -217,23 +206,20 @@ objc_sync_enter (id object)
lock_node_ptr unused_node; lock_node_ptr unused_node;
if (object == nil) if (object == nil)
{
return OBJC_SYNC_SUCCESS; return OBJC_SYNC_SUCCESS;
}
#ifndef SYNC_CACHE_DISABLE #ifndef SYNC_CACHE_DISABLE
if (lock_cache == NULL) if (lock_cache == NULL)
{ {
/* Note that this calloc only happen only once per thread, the /* Note that this calloc only happen only once per thread, the
very first time a thread does a objc_sync_enter(). very first time a thread does a objc_sync_enter(). */
*/
lock_cache = objc_calloc (SYNC_CACHE_SIZE, sizeof (lock_node_ptr)); lock_cache = objc_calloc (SYNC_CACHE_SIZE, sizeof (lock_node_ptr));
} }
/* Check the cache to see if we have a record of having already /* Check the cache to see if we have a record of having already
locked the lock corresponding to this object. While doing so, locked the lock corresponding to this object. While doing so,
keep track of the first free cache node in case we need it later. keep track of the first free cache node in case we need it
*/ later. */
node = NULL; node = NULL;
free_cache_slot = -1; free_cache_slot = -1;
...@@ -246,10 +232,8 @@ objc_sync_enter (id object) ...@@ -246,10 +232,8 @@ objc_sync_enter (id object)
if (locked_node == NULL) if (locked_node == NULL)
{ {
if (free_cache_slot == -1) if (free_cache_slot == -1)
{
free_cache_slot = i; free_cache_slot = i;
} }
}
else if (locked_node->object == object) else if (locked_node->object == object)
{ {
node = locked_node; node = locked_node;
...@@ -261,26 +245,22 @@ objc_sync_enter (id object) ...@@ -261,26 +245,22 @@ objc_sync_enter (id object)
if (node != NULL) if (node != NULL)
{ {
/* We found the lock. Increase recursive_usage_count, which is /* We found the lock. Increase recursive_usage_count, which is
protected by node->lock, which we already hold. protected by node->lock, which we already hold. */
*/
node->recursive_usage_count++; node->recursive_usage_count++;
/* There is no need to actually lock anything, since we already /* There is no need to actually lock anything, since we already
hold the lock. Correspondingly, objc_sync_exit() will just hold the lock. Correspondingly, objc_sync_exit() will just
decrease recursive_usage_count and do nothing to unlock. decrease recursive_usage_count and do nothing to unlock. */
*/
return OBJC_SYNC_SUCCESS; return OBJC_SYNC_SUCCESS;
} }
#endif /* SYNC_CACHE_DISABLE */ #endif /* SYNC_CACHE_DISABLE */
/* The following is the standard lookup for the lock in the standard /* The following is the standard lookup for the lock in the standard
pool lock. It requires a pool protection lock. pool lock. It requires a pool protection lock. */
*/
hash = SYNC_OBJECT_HASH(object); hash = SYNC_OBJECT_HASH(object);
/* Search for an existing lock for 'object'. While searching, make /* Search for an existing lock for 'object'. While searching, make
note of any unused lock if we find any. note of any unused lock if we find any. */
*/
unused_node = NULL; unused_node = NULL;
objc_mutex_lock (sync_pool_protection_locks[hash]); objc_mutex_lock (sync_pool_protection_locks[hash]);
...@@ -298,9 +278,7 @@ objc_sync_enter (id object) ...@@ -298,9 +278,7 @@ objc_sync_enter (id object)
#ifndef SYNC_CACHE_DISABLE #ifndef SYNC_CACHE_DISABLE
/* Put it in the cache. */ /* Put it in the cache. */
if (free_cache_slot != -1) if (free_cache_slot != -1)
{
lock_cache[free_cache_slot] = node; lock_cache[free_cache_slot] = node;
}
#endif #endif
/* Lock it. */ /* Lock it. */
...@@ -329,9 +307,7 @@ objc_sync_enter (id object) ...@@ -329,9 +307,7 @@ objc_sync_enter (id object)
#ifndef SYNC_CACHE_DISABLE #ifndef SYNC_CACHE_DISABLE
if (free_cache_slot != -1) if (free_cache_slot != -1)
{
lock_cache[free_cache_slot] = unused_node; lock_cache[free_cache_slot] = unused_node;
}
#endif #endif
objc_mutex_lock (unused_node->lock); objc_mutex_lock (unused_node->lock);
...@@ -357,9 +333,7 @@ objc_sync_enter (id object) ...@@ -357,9 +333,7 @@ objc_sync_enter (id object)
#ifndef SYNC_CACHE_DISABLE #ifndef SYNC_CACHE_DISABLE
if (free_cache_slot != -1) if (free_cache_slot != -1)
{
lock_cache[free_cache_slot] = new_node; lock_cache[free_cache_slot] = new_node;
}
#endif #endif
objc_mutex_lock (new_node->lock); objc_mutex_lock (new_node->lock);
...@@ -375,9 +349,7 @@ objc_sync_exit (id object) ...@@ -375,9 +349,7 @@ objc_sync_exit (id object)
lock_node_ptr node; lock_node_ptr node;
if (object == nil) if (object == nil)
{
return OBJC_SYNC_SUCCESS; return OBJC_SYNC_SUCCESS;
}
#ifndef SYNC_CACHE_DISABLE #ifndef SYNC_CACHE_DISABLE
if (lock_cache != NULL) if (lock_cache != NULL)
...@@ -399,7 +371,6 @@ objc_sync_exit (id object) ...@@ -399,7 +371,6 @@ objc_sync_exit (id object)
/* Note that, if a node was found in the cache, the variable i /* Note that, if a node was found in the cache, the variable i
now holds the index where it was found, which will be used to now holds the index where it was found, which will be used to
remove it from the cache. */ remove it from the cache. */
if (node != NULL) if (node != NULL)
{ {
if (node->recursive_usage_count > 0) if (node->recursive_usage_count > 0)
...@@ -413,8 +384,8 @@ objc_sync_exit (id object) ...@@ -413,8 +384,8 @@ objc_sync_exit (id object)
hash = SYNC_OBJECT_HASH(object); hash = SYNC_OBJECT_HASH(object);
/* TODO: If we had atomic increase/decrease operations /* TODO: If we had atomic increase/decrease operations
with memory barriers, we could avoid the lock here! with memory barriers, we could avoid the lock
*/ here! */
objc_mutex_lock (sync_pool_protection_locks[hash]); objc_mutex_lock (sync_pool_protection_locks[hash]);
node->usage_count--; node->usage_count--;
/* Normally, we do not reset object to nil here. We'll /* Normally, we do not reset object to nil here. We'll
...@@ -430,8 +401,7 @@ objc_sync_exit (id object) ...@@ -430,8 +401,7 @@ objc_sync_exit (id object)
object from being released. In that case, we remove object from being released. In that case, we remove
it (TODO: maybe we should avoid using the garbage it (TODO: maybe we should avoid using the garbage
collector at all ? Nothing is ever deallocated in collector at all ? Nothing is ever deallocated in
this file). this file). */
*/
#if OBJC_WITH_GC #if OBJC_WITH_GC
node->object = nil; node->object = nil;
#endif #endif
...@@ -442,8 +412,7 @@ objc_sync_exit (id object) ...@@ -442,8 +412,7 @@ objc_sync_exit (id object)
objc_mutex_unlock (node->lock), the pool is unlocked objc_mutex_unlock (node->lock), the pool is unlocked
so other threads may allocate this same lock to so other threads may allocate this same lock to
another object (!). This is not a problem, but it is another object (!). This is not a problem, but it is
curious. curious. */
*/
objc_mutex_unlock (node->lock); objc_mutex_unlock (node->lock);
/* Remove the node from the cache. */ /* Remove the node from the cache. */
...@@ -476,9 +445,7 @@ objc_sync_exit (id object) ...@@ -476,9 +445,7 @@ objc_sync_exit (id object)
objc_mutex_unlock (node->lock); objc_mutex_unlock (node->lock);
/* No need to remove the node from the cache, since it /* No need to remove the node from the cache, since it
wasn't found in the cache when we looked for it! wasn't found in the cache when we looked for it! */
*/
return OBJC_SYNC_SUCCESS; return OBJC_SYNC_SUCCESS;
} }
......
...@@ -123,11 +123,8 @@ object_setClass (id object, Class class_) ...@@ -123,11 +123,8 @@ object_setClass (id object, Class class_)
} }
} }
/* /* Hook functions for memory allocation and disposal. Deprecated and
Hook functions for memory allocation and disposal. Deprecated currently unused. */
and currently unused.
*/
id (*_objc_object_alloc) (Class) = 0; id (*_objc_object_alloc) (Class) = 0;
id (*_objc_object_dispose) (id) = 0; id (*_objc_object_dispose) (id) = 0;
id (*_objc_object_copy) (id) = 0; id (*_objc_object_copy) (id) = 0;
...@@ -69,9 +69,7 @@ __objc_protocols_add_protocol (const char *name, Protocol *object) ...@@ -69,9 +69,7 @@ __objc_protocols_add_protocol (const char *name, Protocol *object)
Objective-C programs while trying to catch a problem that has Objective-C programs while trying to catch a problem that has
never been seen in practice, so we don't do it. */ never been seen in practice, so we don't do it. */
if (! objc_hash_is_key_in_hash (__protocols_hashtable, name)) if (! objc_hash_is_key_in_hash (__protocols_hashtable, name))
{
objc_hash_add (&__protocols_hashtable, name, object); objc_hash_add (&__protocols_hashtable, name, object);
}
objc_mutex_unlock (__protocols_hashtable_lock); objc_mutex_unlock (__protocols_hashtable_lock);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment