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

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

        * init.c (__objc_init_protocol): New function which fixes up a
        protocol's class pointer, registers it with the runtime, register
        all protocol selectors and registers associated protocols too.
        (objc_init_statics): Detect if we are initializing protocols, and
        if so, use __objc_init_protocol instead of only fixing up the
        class pointer.
        (__objc_init_protocls): Use __objc_init_protocol.
        * objc-private/module-abi-8.h: Updated comments.
        * objc-private/runtime.h
        (__objc_register_selectors_from_description_list): New.
        * selector.c (__objc_register_selectors_from_description_list):
        New.  (struct objc_method_description_list): Declare.
        * Protocol.m ([-descriptionForInstanceMethod:]): Use sel_get_name
        when accessing the name of a method, which is now correctly a SEL.
        ([-descriptionForClassMethod:]): Same change.
        * protocols.c (protocol_getMethodDescription): Same change.
        * objc/runtime.h: Updated comments.
        (sel_registerTypedName): Fixed typo in function name.

From-SVN: r165499
This commit is contained in:
Nicola Pero 2010-10-15 10:35:00 +00:00 committed by Nicola Pero
parent fbbf834e27
commit f7185d4791
8 changed files with 152 additions and 42 deletions

View file

@ -1,3 +1,24 @@
2010-10-14 Nicola Pero <nicola.pero@meta-innovation.com>
* init.c (__objc_init_protocol): New function which fixes up a
protocol's class pointer, registers it with the runtime, register
all protocol selectors and registers associated protocols too.
(objc_init_statics): Detect if we are initializing protocols, and
if so, use __objc_init_protocol instead of only fixing up the
class pointer.
(__objc_init_protocls): Use __objc_init_protocol.
* objc-private/module-abi-8.h: Updated comments.
* objc-private/runtime.h
(__objc_register_selectors_from_description_list): New.
* selector.c (__objc_register_selectors_from_description_list):
New. (struct objc_method_description_list): Declare.
* Protocol.m ([-descriptionForInstanceMethod:]): Use sel_get_name
when accessing the name of a method, which is now correctly a SEL.
([-descriptionForClassMethod:]): Same change.
* protocols.c (protocol_getMethodDescription): Same change.
* objc/runtime.h: Updated comments.
(sel_registerTypedName): Fixed typo in function name.
2010-10-13 Nicola Pero <nicola.pero@meta-innovation.com> 2010-10-13 Nicola Pero <nicola.pero@meta-innovation.com>
PR libobjc/23214 PR libobjc/23214

View file

@ -85,7 +85,7 @@ struct objc_method_description_list {
if (instance_methods) if (instance_methods)
for (i = 0; i < instance_methods->count; i++) for (i = 0; i < instance_methods->count; i++)
{ {
if (!strcmp ((char*)instance_methods->list[i].name, name)) if (!strcmp (sel_get_name (instance_methods->list[i].name), name))
return &(instance_methods->list[i]); return &(instance_methods->list[i]);
} }
@ -113,7 +113,7 @@ struct objc_method_description_list {
if (class_methods) if (class_methods)
for (i = 0; i < class_methods->count; i++) for (i = 0; i < class_methods->count; i++)
{ {
if (!strcmp ((char*)class_methods->list[i].name, name)) if (!strcmp (sel_get_name (class_methods->list[i].name), name))
return &(class_methods->list[i]); return &(class_methods->list[i]);
} }

View file

@ -32,7 +32,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#include "objc-private/objc-list.h" #include "objc-private/objc-list.h"
#include "objc-private/runtime.h" #include "objc-private/runtime.h"
#include "objc-private/objc-sync.h" /* For __objc_sync_init() */ #include "objc-private/objc-sync.h" /* For __objc_sync_init() */
#include "objc-private/protocols.h" /* For __objc_protocols_init() and __objc_protocols_add_protocol() */ #include "objc-private/protocols.h" /* For __objc_protocols_init(),
__objc_protocols_add_protocol()
__objc_protocols_register_selectors() */
/* The version number of this runtime. This must match the number /* The version number of this runtime. This must match the number
defined in gcc (objc-act.c). */ defined in gcc (objc-act.c). */
@ -70,6 +72,9 @@ static void init_check_module_version (Module_t);
/* Assign isa links to protos. */ /* Assign isa links to protos. */
static void __objc_init_protocols (struct objc_protocol_list *protos); static void __objc_init_protocols (struct objc_protocol_list *protos);
/* Assign isa link to a protocol, and register it. */
static void __objc_init_protocol (struct objc_protocol *protocol);
/* Add protocol to class. */ /* Add protocol to class. */
static void __objc_class_add_protocols (Class, struct objc_protocol_list *); static void __objc_class_add_protocols (Class, struct objc_protocol_list *);
@ -490,11 +495,27 @@ objc_init_statics (void)
they were attached to classes or categories, and the they were attached to classes or categories, and the
class/category loading code automatically fixes them class/category loading code automatically fixes them
up), and some of them may not. We really need to go up), and some of them may not. We really need to go
through the whole list to be sure! */ through the whole list to be sure! Protocols are
also special because we want to register them and
register all their selectors. */
id *inst; id *inst;
for (inst = &statics->instances[0]; *inst; inst++) if (strcmp (statics->class_name, "Protocol") == 0)
(*inst)->class_pointer = class; {
/* Protocols are special, because not only we want
to fix up their class pointers, but we also want
to register them and their selectors with the
runtime. */
for (inst = &statics->instances[0]; *inst; inst++)
__objc_init_protocol ((struct objc_protocol *)*inst);
}
else
{
/* Other static instances (typically constant strings) are
easier as we just fix up their class pointers. */
for (inst = &statics->instances[0]; *inst; inst++)
(*inst)->class_pointer = class;
}
} }
} }
if (module_initialized) if (module_initialized)
@ -843,6 +864,49 @@ init_check_module_version (Module_t module)
} }
} }
/* __objc_init_protocol must be called with __objc_runtime_mutex
already locked, and the "Protocol" class already registered. */
static void
__objc_init_protocol (struct objc_protocol *protocol)
{
static Class proto_class = 0;
if (! proto_class)
proto_class = objc_get_class ("Protocol");
if (((size_t)protocol->class_pointer) == PROTOCOL_VERSION)
{
/* Assign class pointer */
protocol->class_pointer = proto_class;
/* Register all the selectors in the protocol with the runtime.
This both registers the selectors with the right types, and
it also fixes up the 'struct objc_method' structures inside
the protocol so that each method_name (a char * as compiled
by the compiler) is replaced with the appropriate runtime
SEL. */
if (protocol->class_methods)
__objc_register_selectors_from_description_list (protocol->class_methods);
if (protocol->instance_methods)
__objc_register_selectors_from_description_list (protocol->instance_methods);
/* Register the protocol in the hashtable or protocols by
name. */
__objc_protocols_add_protocol (protocol->protocol_name, protocol);
/* Init super protocols */
__objc_init_protocols (protocol->protocol_list);
}
else if (protocol->class_pointer != proto_class)
{
_objc_abort ("Version %d doesn't match runtime protocol version %d\n",
(int) ((char *) protocol->class_pointer
- (char *) 0),
PROTOCOL_VERSION);
}
}
static void static void
__objc_init_protocols (struct objc_protocol_list *protos) __objc_init_protocols (struct objc_protocol_list *protos)
{ {
@ -871,25 +935,7 @@ __objc_init_protocols (struct objc_protocol_list *protos)
for (i = 0; i < protos->count; i++) for (i = 0; i < protos->count; i++)
{ {
struct objc_protocol *aProto = protos->list[i]; struct objc_protocol *aProto = protos->list[i];
if (((size_t)aProto->class_pointer) == PROTOCOL_VERSION) __objc_init_protocol (aProto);
{
/* Assign class pointer */
aProto->class_pointer = proto_class;
/* Register the protocol in the hashtable or protocols by
name. */
__objc_protocols_add_protocol (aProto->protocol_name, aProto);
/* Init super protocols */
__objc_init_protocols (aProto->protocol_list);
}
else if (protos->list[i]->class_pointer != proto_class)
{
_objc_abort ("Version %d doesn't match runtime protocol version %d\n",
(int) ((char *) protos->list[i]->class_pointer
- (char *) 0),
PROTOCOL_VERSION);
}
} }
objc_mutex_unlock (__objc_runtime_mutex); objc_mutex_unlock (__objc_runtime_mutex);

View file

@ -115,13 +115,15 @@ struct objc_ivar_list
problem is a singly linked list of methods. */ problem is a singly linked list of methods. */
struct objc_method struct objc_method
{ {
SEL method_name; /* This variable is the method's name. It SEL method_name; /* This variable is the method's name.
is a char*. The unique integer passed The compiler puts a char* here, and
to objc_msg_send is a char* too. It is it's replaced by a real SEL at runtime
compared against method_name using when the method is registered. */
strcmp. */
const char* method_types; /* Description of the method's parameter const char* method_types; /* Description of the method's parameter
list. Useful for debuggers. */ list. Used when registering the
selector with the runtime. When that
happens, method_name will contain the
method's parameter list. */
IMP method_imp; /* Address of the method in the IMP method_imp; /* Address of the method in the
executable. */ executable. */
}; };
@ -139,7 +141,12 @@ struct objc_method_list
}; };
/* Currently defined in Protocol.m (that definition should go away /* Currently defined in Protocol.m (that definition should go away
once we include this file). */ once we include this file). Note that a 'struct
objc_method_description' as embedded inside a Protocol uses the
same trick as a 'struct objc_method': the method_name is a 'char *'
according to the compiler, who puts the method name as a string in
there. At runtime, the selectors need to be registered, and the
method_name then becomes a SEL. */
struct objc_method_description_list struct objc_method_description_list
{ {
int count; int count;

View file

@ -60,6 +60,8 @@ extern void __objc_install_premature_dtable(Class); /* (objc-dispatch.c) */
extern void __objc_resolve_class_links(void); /* (objc-class.c) */ extern void __objc_resolve_class_links(void); /* (objc-class.c) */
extern void __objc_register_selectors_from_class(Class); /* (objc-sel.c) */ extern void __objc_register_selectors_from_class(Class); /* (objc-sel.c) */
extern void __objc_register_selectors_from_list (struct objc_method_list *); /* (selector.c) */ extern void __objc_register_selectors_from_list (struct objc_method_list *); /* (selector.c) */
extern void __objc_register_selectors_from_description_list
(struct objc_method_description_list *method_list); /* (selector.c) */
extern void __objc_update_dispatch_table_for_class (Class);/* (objc-msg.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_init_thread_system(void); /* thread.c */

View file

@ -195,7 +195,7 @@ objc_EXPORT SEL sel_registerName (const char *name);
Compatibility Note: the Apple/NeXT runtime has untyped selectors, Compatibility Note: the Apple/NeXT runtime has untyped selectors,
so it does not have this function, which is specific to the GNU so it does not have this function, which is specific to the GNU
Runtime. */ Runtime. */
objc_EXPORT SEL set_registerTypedName (const char *name, const char *type); objc_EXPORT SEL sel_registerTypedName (const char *name, const char *type);
/* Return YES if first_selector is the same as second_selector, and NO /* Return YES if first_selector is the same as second_selector, and NO
if not. */ if not. */
@ -505,7 +505,7 @@ objc_EXPORT Method * class_copyMethodList (Class class_, unsigned int *numberOfR
objc_EXPORT unsigned int method_getNumberOfArguments (Method method); objc_EXPORT unsigned int method_getNumberOfArguments (Method method);
/* Return the string encoding for the return type of method 'method'. /* Return the string encoding for the return type of method 'method'.
The string is a standard NULL-terminated string in an area of The string is a standard zero-terminated string in an area of
memory allocated with malloc(); you should free it with free() when memory allocated with malloc(); you should free it with free() when
you finish using it. Return an empty string if method is NULL. */ you finish using it. Return an empty string if method is NULL. */
objc_EXPORT char * method_copyReturnType (Method method); objc_EXPORT char * method_copyReturnType (Method method);
@ -513,7 +513,7 @@ objc_EXPORT char * method_copyReturnType (Method method);
/* Return the string encoding for the argument type of method /* Return the string encoding for the argument type of method
'method', argument number 'argumentNumber' ('argumentNumber' is 0 'method', argument number 'argumentNumber' ('argumentNumber' is 0
for self, 1 for _cmd, and 2 or more for the additional arguments if for self, 1 for _cmd, and 2 or more for the additional arguments if
any). The string is a standard NULL-terminated string in an area any). The string is a standard zero-terminated string in an area
of memory allocated with malloc(); you should free it with free() of memory allocated with malloc(); you should free it with free()
when you finish using it. Return an empty string if method is NULL when you finish using it. Return an empty string if method is NULL
or if 'argumentNumber' refers to a non-existing argument. */ or if 'argumentNumber' refers to a non-existing argument. */
@ -524,10 +524,10 @@ objc_EXPORT char * method_copyArgumentType (Method method, unsigned int argument
'returnValue' string, which is of size 'returnValueSize'. No more 'returnValue' string, which is of size 'returnValueSize'. No more
than 'returnValueSize' characters are copied; if the encoding is than 'returnValueSize' characters are copied; if the encoding is
smaller than 'returnValueSize', the rest of 'returnValue' is filled smaller than 'returnValueSize', the rest of 'returnValue' is filled
with NULLs. If it is bigger, it is truncated (and would not be with zeros. If it is bigger, it is truncated (and would not be
NULL-terminated). You should supply a big enough zero-terminated). You should supply a big enough
'returnValueSize'. If the method is NULL, returnValue is set to a 'returnValueSize'. If the method is NULL, returnValue is set to a
string of NULLs. */ string of zeros. */
objc_EXPORT void method_getReturnType (Method method, char *returnValue, objc_EXPORT void method_getReturnType (Method method, char *returnValue,
size_t returnValueSize); size_t returnValueSize);
@ -538,10 +538,10 @@ objc_EXPORT void method_getReturnType (Method method, char *returnValue,
'returnValue' string, which is of size 'returnValueSize'. No more 'returnValue' string, which is of size 'returnValueSize'. No more
than 'returnValueSize' characters are copied; if the encoding is than 'returnValueSize' characters are copied; if the encoding is
smaller than 'returnValueSize', the rest of 'returnValue' is filled smaller than 'returnValueSize', the rest of 'returnValue' is filled
with NULLs. If it is bigger, it is truncated (and would not be with zeros. If it is bigger, it is truncated (and would not be
NULL-terminated). You should supply a big enough zero-terminated). You should supply a big enough
'returnValueSize'. If the method is NULL, returnValue is set to a 'returnValueSize'. If the method is NULL, returnValue is set to a
string of NULLs. */ string of zeros. */
objc_EXPORT void method_getArgumentType (Method method, unsigned int argumentNumber, objc_EXPORT void method_getArgumentType (Method method, unsigned int argumentNumber,
char *returnValue, size_t returnValueSize); char *returnValue, size_t returnValueSize);

View file

@ -383,7 +383,7 @@ struct objc_method_description protocol_getMethodDescription (Protocol *protocol
{ {
for (i = 0; i < methods->count; i++) for (i = 0; i < methods->count; i++)
{ {
if (strcmp ((char*)(methods->list[i].name), selector_name) == 0) if (strcmp (sel_getName (methods->list[i].name), selector_name) == 0)
return methods->list[i]; return methods->list[i];
} }
} }

View file

@ -95,6 +95,40 @@ __objc_register_selectors_from_list (MethodList_t method_list)
objc_mutex_unlock (__objc_runtime_mutex); objc_mutex_unlock (__objc_runtime_mutex);
} }
/* Temporary definition while we include objc/objc-api.h instead of
objc-private/module-abi-8.h. It should go away once we include
module-abi-8.h. */
struct objc_method_description_list
{
int count;
struct objc_method_description list[1];
};
/* The same as __objc_register_selectors_from_list, but works on a
struct objc_method_description_list* instead of a struct
objc_method_list*. This is only used for protocols, which have
lists of method descriptions, not methods.
*/
void
__objc_register_selectors_from_description_list
(struct objc_method_description_list *method_list)
{
int i = 0;
objc_mutex_lock (__objc_runtime_mutex);
while (i < method_list->count)
{
struct objc_method_description *method = &method_list->list[i];
if (method->name)
{
method->name
= __sel_register_typed_name ((const char *) method->name,
method->types, 0, YES);
}
i += 1;
}
objc_mutex_unlock (__objc_runtime_mutex);
}
/* Register instance methods as class methods for root classes */ /* Register instance methods as class methods for root classes */
void __objc_register_instance_methods_to_class (Class class) void __objc_register_instance_methods_to_class (Class class)