mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 08:26:27 +00:00
(class_add_methods_if_not_there): Only put method implementation in
dtable if the dtable is already installed, otherwise, just add it to the class's methods list and let __objc_install_dispatch_table_for_class put it in. Also, change arguments. All callers updated. (check_class_methods): New function. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@284 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
25b5e6b3be
commit
dd4444884d
2 changed files with 172 additions and 32 deletions
|
@ -38,6 +38,11 @@
|
|||
If you add several behaviors to a class, be aware that the order of
|
||||
the additions is significant.
|
||||
|
||||
McCallum talking to himself:
|
||||
"Yipes. Be careful with [super ...] calls.
|
||||
BEHAVIOR methods running in CLASS will now have a different super class.
|
||||
No; wrong. See objc-api.h; typedef struct objc_super."
|
||||
|
||||
*/
|
||||
|
||||
#include <objc/objc.h>
|
||||
|
@ -56,7 +61,12 @@ static void __objc_class_add_protocols (Class class,
|
|||
struct objc_protocol_list* protos);
|
||||
#endif
|
||||
static BOOL class_is_kind_of(Class self, Class class);
|
||||
void class_add_methods_if_not_there(Class class, MethodList_t mlist);
|
||||
static void check_class_methods(Class class);
|
||||
|
||||
void class_add_methods_if_not_there(Class class, Class behavior);
|
||||
|
||||
/* The uninstalled dispatch table, declared in gcc/objc/sendmsg.c. */
|
||||
extern struct sarray* __objc_uninstalled_dtable;
|
||||
|
||||
/* xxx consider using sendmsg.c:__objc_update_dispatch_table_for_class,
|
||||
but, I think it will be slower than the current method. */
|
||||
|
@ -89,12 +99,21 @@ class_add_behavior (Class class, Class behavior)
|
|||
#endif
|
||||
|
||||
/* Add instance methods */
|
||||
class_add_methods_if_not_there(class,
|
||||
behavior->methods);
|
||||
if (behavior_debug)
|
||||
{
|
||||
fprintf(stderr, "Adding instance methods from %s\n",
|
||||
behavior->name);
|
||||
}
|
||||
class_add_methods_if_not_there(class, behavior);
|
||||
|
||||
/* Add class methods */
|
||||
if (behavior_debug)
|
||||
{
|
||||
fprintf(stderr, "Adding class methods from %s\n",
|
||||
behavior->class_pointer->name);
|
||||
}
|
||||
class_add_methods_if_not_there(class->class_pointer,
|
||||
behavior->class_pointer->methods);
|
||||
behavior->class_pointer);
|
||||
|
||||
/* Add behavior's superclass, if not already there. */
|
||||
{
|
||||
|
@ -106,15 +125,16 @@ class_add_behavior (Class class, Class behavior)
|
|||
}
|
||||
|
||||
void
|
||||
class_add_methods_if_not_there(Class class, MethodList_t mlist)
|
||||
class_add_methods_if_not_there(Class class, Class behavior)
|
||||
{
|
||||
static SEL initialize_sel = 0;
|
||||
MethodList_t mlist;
|
||||
|
||||
if (!initialize_sel)
|
||||
initialize_sel = sel_register_name ("initialize");
|
||||
|
||||
/* Add methods to class->dtable and class->methods */
|
||||
for ( ; mlist; mlist = mlist->method_next)
|
||||
for (mlist = behavior->methods; mlist; mlist = mlist->method_next)
|
||||
{
|
||||
int counter;
|
||||
MethodList_t new_list;
|
||||
|
@ -125,7 +145,7 @@ class_add_methods_if_not_there(Class class, MethodList_t mlist)
|
|||
all methods will go in here. */
|
||||
new_list = (MethodList_t)
|
||||
(*objc_malloc)
|
||||
(sizeof(MethodList) + sizeof(struct objc_method[counter]));
|
||||
(sizeof(MethodList) + sizeof(struct objc_method[counter+1]));
|
||||
new_list->method_count = 0;
|
||||
|
||||
while (counter >= 0)
|
||||
|
@ -133,7 +153,7 @@ class_add_methods_if_not_there(Class class, MethodList_t mlist)
|
|||
Method_t method = &(mlist->method_list[counter]);
|
||||
|
||||
if (behavior_debug)
|
||||
fprintf(stderr, "processing method %s\n",
|
||||
fprintf(stderr, " processing method [%s]\n",
|
||||
sel_get_name(method->method_name));
|
||||
|
||||
if (!search_for_method_in_list(class->methods, method->method_name)
|
||||
|
@ -142,19 +162,38 @@ class_add_methods_if_not_there(Class class, MethodList_t mlist)
|
|||
/* As long as the method isn't defined in the CLASS,
|
||||
put the BEHAVIOR method in there. Thus, behavior
|
||||
methods override the superclasses' methods. */
|
||||
sarray_at_put_safe (class->dtable,
|
||||
(sidx) method->method_name->sel_id,
|
||||
method->method_imp);
|
||||
|
||||
/* If dtable is already installed, go ahead and put it in
|
||||
the dtable sarray, but if it isn't, let
|
||||
__objc_install_dispatch_table_for_class do it. */
|
||||
|
||||
if (class->dtable != __objc_uninstalled_dtable)
|
||||
{
|
||||
sarray_at_put_safe (class->dtable,
|
||||
(sidx) method->method_name->sel_id,
|
||||
method->method_imp);
|
||||
if (behavior_debug)
|
||||
fprintf(stderr, "\tinstalled method\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (behavior_debug)
|
||||
fprintf(stderr, "\tappended method\n");
|
||||
}
|
||||
new_list->method_list[new_list->method_count] = *method;
|
||||
(new_list->method_count)++;
|
||||
if (behavior_debug)
|
||||
fprintf(stderr, "added method %s\n",
|
||||
sel_get_name(method->method_name));
|
||||
}
|
||||
counter -= 1;
|
||||
}
|
||||
new_list->method_next = class->methods;
|
||||
class->methods = new_list;
|
||||
if (new_list->method_count)
|
||||
{
|
||||
new_list->method_next = class->methods;
|
||||
class->methods = new_list;
|
||||
}
|
||||
else
|
||||
{
|
||||
OBJC_FREE(new_list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -354,3 +393,34 @@ static BOOL class_is_kind_of(Class self, Class aClassObject)
|
|||
return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
void
|
||||
check_class_methods(Class class)
|
||||
{
|
||||
int counter;
|
||||
MethodList_t mlist;
|
||||
|
||||
if (class->dtable == __objc_uninstalled_dtable)
|
||||
return;
|
||||
|
||||
for (mlist = class->methods; mlist; mlist = mlist->method_next)
|
||||
{
|
||||
counter = mlist->method_count - 1;
|
||||
while (counter >= 0)
|
||||
{
|
||||
Method_t method = &(mlist->method_list[counter]);
|
||||
IMP imp = sarray_get(class->dtable,
|
||||
(size_t)method->method_name->sel_id);
|
||||
assert((imp == method->method_imp));
|
||||
sarray_at_put_safe (class->dtable,
|
||||
(sidx) method->method_name->sel_id,
|
||||
method->method_imp);
|
||||
counter -= 1;
|
||||
}
|
||||
}
|
||||
if (class->super_class)
|
||||
check_class_methods(class->super_class);
|
||||
|
||||
(void) &check_class_methods; /* to prevent compiler warning about unused */
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,11 @@
|
|||
If you add several behaviors to a class, be aware that the order of
|
||||
the additions is significant.
|
||||
|
||||
McCallum talking to himself:
|
||||
"Yipes. Be careful with [super ...] calls.
|
||||
BEHAVIOR methods running in CLASS will now have a different super class.
|
||||
No; wrong. See objc-api.h; typedef struct objc_super."
|
||||
|
||||
*/
|
||||
|
||||
#include <objc/objc.h>
|
||||
|
@ -56,7 +61,12 @@ static void __objc_class_add_protocols (Class class,
|
|||
struct objc_protocol_list* protos);
|
||||
#endif
|
||||
static BOOL class_is_kind_of(Class self, Class class);
|
||||
void class_add_methods_if_not_there(Class class, MethodList_t mlist);
|
||||
static void check_class_methods(Class class);
|
||||
|
||||
void class_add_methods_if_not_there(Class class, Class behavior);
|
||||
|
||||
/* The uninstalled dispatch table, declared in gcc/objc/sendmsg.c. */
|
||||
extern struct sarray* __objc_uninstalled_dtable;
|
||||
|
||||
/* xxx consider using sendmsg.c:__objc_update_dispatch_table_for_class,
|
||||
but, I think it will be slower than the current method. */
|
||||
|
@ -89,12 +99,21 @@ class_add_behavior (Class class, Class behavior)
|
|||
#endif
|
||||
|
||||
/* Add instance methods */
|
||||
class_add_methods_if_not_there(class,
|
||||
behavior->methods);
|
||||
if (behavior_debug)
|
||||
{
|
||||
fprintf(stderr, "Adding instance methods from %s\n",
|
||||
behavior->name);
|
||||
}
|
||||
class_add_methods_if_not_there(class, behavior);
|
||||
|
||||
/* Add class methods */
|
||||
if (behavior_debug)
|
||||
{
|
||||
fprintf(stderr, "Adding class methods from %s\n",
|
||||
behavior->class_pointer->name);
|
||||
}
|
||||
class_add_methods_if_not_there(class->class_pointer,
|
||||
behavior->class_pointer->methods);
|
||||
behavior->class_pointer);
|
||||
|
||||
/* Add behavior's superclass, if not already there. */
|
||||
{
|
||||
|
@ -106,15 +125,16 @@ class_add_behavior (Class class, Class behavior)
|
|||
}
|
||||
|
||||
void
|
||||
class_add_methods_if_not_there(Class class, MethodList_t mlist)
|
||||
class_add_methods_if_not_there(Class class, Class behavior)
|
||||
{
|
||||
static SEL initialize_sel = 0;
|
||||
MethodList_t mlist;
|
||||
|
||||
if (!initialize_sel)
|
||||
initialize_sel = sel_register_name ("initialize");
|
||||
|
||||
/* Add methods to class->dtable and class->methods */
|
||||
for ( ; mlist; mlist = mlist->method_next)
|
||||
for (mlist = behavior->methods; mlist; mlist = mlist->method_next)
|
||||
{
|
||||
int counter;
|
||||
MethodList_t new_list;
|
||||
|
@ -125,7 +145,7 @@ class_add_methods_if_not_there(Class class, MethodList_t mlist)
|
|||
all methods will go in here. */
|
||||
new_list = (MethodList_t)
|
||||
(*objc_malloc)
|
||||
(sizeof(MethodList) + sizeof(struct objc_method[counter]));
|
||||
(sizeof(MethodList) + sizeof(struct objc_method[counter+1]));
|
||||
new_list->method_count = 0;
|
||||
|
||||
while (counter >= 0)
|
||||
|
@ -133,7 +153,7 @@ class_add_methods_if_not_there(Class class, MethodList_t mlist)
|
|||
Method_t method = &(mlist->method_list[counter]);
|
||||
|
||||
if (behavior_debug)
|
||||
fprintf(stderr, "processing method %s\n",
|
||||
fprintf(stderr, " processing method [%s]\n",
|
||||
sel_get_name(method->method_name));
|
||||
|
||||
if (!search_for_method_in_list(class->methods, method->method_name)
|
||||
|
@ -142,19 +162,38 @@ class_add_methods_if_not_there(Class class, MethodList_t mlist)
|
|||
/* As long as the method isn't defined in the CLASS,
|
||||
put the BEHAVIOR method in there. Thus, behavior
|
||||
methods override the superclasses' methods. */
|
||||
sarray_at_put_safe (class->dtable,
|
||||
(sidx) method->method_name->sel_id,
|
||||
method->method_imp);
|
||||
|
||||
/* If dtable is already installed, go ahead and put it in
|
||||
the dtable sarray, but if it isn't, let
|
||||
__objc_install_dispatch_table_for_class do it. */
|
||||
|
||||
if (class->dtable != __objc_uninstalled_dtable)
|
||||
{
|
||||
sarray_at_put_safe (class->dtable,
|
||||
(sidx) method->method_name->sel_id,
|
||||
method->method_imp);
|
||||
if (behavior_debug)
|
||||
fprintf(stderr, "\tinstalled method\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (behavior_debug)
|
||||
fprintf(stderr, "\tappended method\n");
|
||||
}
|
||||
new_list->method_list[new_list->method_count] = *method;
|
||||
(new_list->method_count)++;
|
||||
if (behavior_debug)
|
||||
fprintf(stderr, "added method %s\n",
|
||||
sel_get_name(method->method_name));
|
||||
}
|
||||
counter -= 1;
|
||||
}
|
||||
new_list->method_next = class->methods;
|
||||
class->methods = new_list;
|
||||
if (new_list->method_count)
|
||||
{
|
||||
new_list->method_next = class->methods;
|
||||
class->methods = new_list;
|
||||
}
|
||||
else
|
||||
{
|
||||
OBJC_FREE(new_list);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -354,3 +393,34 @@ static BOOL class_is_kind_of(Class self, Class aClassObject)
|
|||
return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
void
|
||||
check_class_methods(Class class)
|
||||
{
|
||||
int counter;
|
||||
MethodList_t mlist;
|
||||
|
||||
if (class->dtable == __objc_uninstalled_dtable)
|
||||
return;
|
||||
|
||||
for (mlist = class->methods; mlist; mlist = mlist->method_next)
|
||||
{
|
||||
counter = mlist->method_count - 1;
|
||||
while (counter >= 0)
|
||||
{
|
||||
Method_t method = &(mlist->method_list[counter]);
|
||||
IMP imp = sarray_get(class->dtable,
|
||||
(size_t)method->method_name->sel_id);
|
||||
assert((imp == method->method_imp));
|
||||
sarray_at_put_safe (class->dtable,
|
||||
(sidx) method->method_name->sel_id,
|
||||
method->method_imp);
|
||||
counter -= 1;
|
||||
}
|
||||
}
|
||||
if (class->super_class)
|
||||
check_class_methods(class->super_class);
|
||||
|
||||
(void) &check_class_methods; /* to prevent compiler warning about unused */
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue