diff options
author | nicola <nicola@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-10-12 22:00:01 +0000 |
---|---|---|
committer | nicola <nicola@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-10-12 22:00:01 +0000 |
commit | 1da9f882a280710491bb5a1148b12b5da60cbe82 (patch) | |
tree | c1e1a95aab3eeed0bec8d3d90946e13dff607e7d | |
parent | 76ab33ff6aebab59cae8c47c8ce8e0099b5aa55d (diff) | |
download | gcc-1da9f882a280710491bb5a1148b12b5da60cbe82.tar.gz |
2010-10-12 Nicola Pero <nicola.pero@meta-innovation.com>
* Makefile.in (C_SOURCE_FILES): Added methods.c.
* encoding.c (method_getNumberOfArguments): New.
(method_get_number_of_arguments): Call
method_getNumberOfArguments.
* ivars.c (ivar_getName): Check for NULL variable argument.
(ivar_getOffset): Check for NULL variable argument.
(ivar_getTypeEncoding): Check for NULL variable argument.
(class_copyIvarList): New.
* methods.c: New.
* protocols.c (class_copyProtocolList): Check for Nil class_
argument.
* sendmsg.c: Use 'struct objc_method *' instead of Method_t, and
'struct objc_method_list *' instead of MethodList_t.
(class_getMethodImplementation): New.
(class_respondsToSelector): New.
(class_getInstanceMethod): New.
(class_getClassMethod): New.
* objc/runtime.h: Updated comments.
(class_copyIvarList): New.
(class_getInstanceMethod): New.
(class_getClassMethod): New.
(class_getMethodImplementation): New.
(class_respondsToSelector): New.
(method_getName): New.
(method_getImplementation): New.
(method_getTypeEncoding): New.
(class_copyMethodList): New.
(method_getNumberOfArguments): New.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@165400 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | libobjc/ChangeLog | 31 | ||||
-rw-r--r-- | libobjc/Makefile.in | 1 | ||||
-rw-r--r-- | libobjc/encoding.c | 43 | ||||
-rw-r--r-- | libobjc/ivars.c | 63 | ||||
-rw-r--r-- | libobjc/methods.c | 114 | ||||
-rw-r--r-- | libobjc/objc/runtime.h | 95 | ||||
-rw-r--r-- | libobjc/protocols.c | 7 | ||||
-rw-r--r-- | libobjc/sendmsg.c | 90 |
8 files changed, 407 insertions, 37 deletions
diff --git a/libobjc/ChangeLog b/libobjc/ChangeLog index ec0a98f3790..300bb3e7e20 100644 --- a/libobjc/ChangeLog +++ b/libobjc/ChangeLog @@ -1,5 +1,36 @@ 2010-10-12 Nicola Pero <nicola.pero@meta-innovation.com> + * Makefile.in (C_SOURCE_FILES): Added methods.c. + * encoding.c (method_getNumberOfArguments): New. + (method_get_number_of_arguments): Call + method_getNumberOfArguments. + * ivars.c (ivar_getName): Check for NULL variable argument. + (ivar_getOffset): Check for NULL variable argument. + (ivar_getTypeEncoding): Check for NULL variable argument. + (class_copyIvarList): New. + * methods.c: New. + * protocols.c (class_copyProtocolList): Check for Nil class_ + argument. + * sendmsg.c: Use 'struct objc_method *' instead of Method_t, and + 'struct objc_method_list *' instead of MethodList_t. + (class_getMethodImplementation): New. + (class_respondsToSelector): New. + (class_getInstanceMethod): New. + (class_getClassMethod): New. + * objc/runtime.h: Updated comments. + (class_copyIvarList): New. + (class_getInstanceMethod): New. + (class_getClassMethod): New. + (class_getMethodImplementation): New. + (class_respondsToSelector): New. + (method_getName): New. + (method_getImplementation): New. + (method_getTypeEncoding): New. + (class_copyMethodList): New. + (method_getNumberOfArguments): New. + +2010-10-12 Nicola Pero <nicola.pero@meta-innovation.com> + * class.c: Include objc/runtime.h and objc-private/module-abi-8.h instead of objc/objc-api.h. (objc_get_unknown_class_handler): Do not define. diff --git a/libobjc/Makefile.in b/libobjc/Makefile.in index 4790f952b9d..b644b3f4832 100644 --- a/libobjc/Makefile.in +++ b/libobjc/Makefile.in @@ -173,6 +173,7 @@ C_SOURCE_FILES = \ init.c \ ivars.c \ memory.c \ + methods.c \ nil_method.c \ objc-foreach.c \ objc-sync.c \ diff --git a/libobjc/encoding.c b/libobjc/encoding.c index 87517f4eaf8..b30389ee0e4 100644 --- a/libobjc/encoding.c +++ b/libobjc/encoding.c @@ -797,22 +797,39 @@ objc_skip_argspec (const char *type) return type; } -/* - Return the number of arguments that the method MTH expects. - Note that all methods need two implicit arguments `self' and - `_cmd'. -*/ -int -method_get_number_of_arguments (struct objc_method *mth) +unsigned int +method_getNumberOfArguments (struct objc_method *method) { - int i = 0; - const char *type = mth->method_types; - while (*type) + if (method == NULL) + return 0; + else { - type = objc_skip_argspec (type); - i += 1; + unsigned int i = 0; + const char *type = method->method_types; + while (*type) + { + type = objc_skip_argspec (type); + i += 1; + } + + if (i == 0) + { + /* This could only happen if method_types is invalid; in + that case, return 0. */ + return 0; + } + else + { + /* Remove the return type. */ + return (i - 1); + } } - return i - 1; +} + +int +method_get_number_of_arguments (struct objc_method *mth) +{ + return method_getNumberOfArguments (mth); } /* diff --git a/libobjc/ivars.c b/libobjc/ivars.c index 52b71af1124..0dbb45b676a 100644 --- a/libobjc/ivars.c +++ b/libobjc/ivars.c @@ -26,8 +26,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #include "objc/runtime.h" #include "objc-private/module-abi-8.h" /* For runtime structures */ #include "objc/thr.h" -#include "objc-private/runtime.h" /* the kitchen sink */ -#include <string.h> /* For strcmp */ +#include "objc-private/runtime.h" /* the kitchen sink */ +#include <string.h> /* For strcmp */ struct objc_ivar * class_getInstanceVariable (Class class_, const char *name) @@ -157,15 +157,74 @@ void object_setIvar (id object, struct objc_ivar * variable, id value) const char * ivar_getName (struct objc_ivar * variable) { + if (variable == NULL) + return NULL; + return variable->ivar_name; } ptrdiff_t ivar_getOffset (struct objc_ivar * variable) { + if (variable == NULL) + return 0; + return (ptrdiff_t)(variable->ivar_offset); } const char * ivar_getTypeEncoding (struct objc_ivar * variable) { + if (variable == NULL) + return NULL; + return variable->ivar_type; } + +struct objc_ivar ** class_copyIvarList (Class class_, unsigned int *numberOfReturnedIvars) +{ + unsigned int count = 0; + struct objc_ivar **returnValue = NULL; + struct objc_ivar_list* ivar_list; + + if (class_ == Nil) + { + if (numberOfReturnedIvars) + *numberOfReturnedIvars = 0; + return NULL; + } + + /* TODO: We do not need to lock the runtime mutex if the class has + been registered with the runtime, since the instance variable + list can not change after the class is registered. The only case + where the lock may be useful if the class is still being created + using objc_allocateClassPair(), but has not been registered using + objc_registerClassPair() yet. I'm not even sure that is + allowed. */ + objc_mutex_lock (__objc_runtime_mutex); + + /* Count how many ivars we have. */ + ivar_list = class_->ivars; + count = ivar_list->ivar_count; + + if (count != 0) + { + unsigned int i = 0; + + /* Allocate enough memory to hold them. */ + returnValue = (struct objc_ivar **)(malloc (sizeof (struct objc_ivar *) * (count + 1))); + + /* Copy the ivars. */ + for (i = 0; i < count; i++) + { + returnValue[i] = &(ivar_list->ivar_list[i]); + } + + returnValue[i] = NULL; + } + + objc_mutex_unlock (__objc_runtime_mutex); + + if (numberOfReturnedIvars) + *numberOfReturnedIvars = count; + + return returnValue; +} diff --git a/libobjc/methods.c b/libobjc/methods.c new file mode 100644 index 00000000000..c6236a100e7 --- /dev/null +++ b/libobjc/methods.c @@ -0,0 +1,114 @@ +/* GNU Objective C Runtime method related functions. + Copyright (C) 2010 Free Software Foundation, Inc. + Contributed by Nicola Pero + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 3, or (at your option) any later version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +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/>. */ + +#include "objc-private/common.h" +#include "objc/runtime.h" +#include "objc-private/module-abi-8.h" /* For runtime structures. */ +#include "objc/thr.h" +#include "objc-private/runtime.h" /* For __objc_runtime_mutex. */ +#include <stdlib.h> /* For malloc. */ + +SEL method_getName (struct objc_method * method) +{ + if (method == NULL) + return NULL; + + return method->method_name; +} + +const char * method_getTypeEncoding (struct objc_method * method) +{ + if (method == NULL) + return NULL; + + return method->method_types; +} + +IMP method_getImplementation (struct objc_method * method) +{ + if (method == NULL) + return NULL; + + return method->method_imp; +} + +struct objc_method ** class_copyMethodList (Class class_, unsigned int *numberOfReturnedMethods) +{ + unsigned int count = 0; + struct objc_method **returnValue = NULL; + struct objc_method_list* method_list; + + if (class_ == Nil) + { + if (numberOfReturnedMethods) + *numberOfReturnedMethods = 0; + return NULL; + } + + /* Lock the runtime mutex because the class methods may be + concurrently modified. */ + objc_mutex_lock (__objc_runtime_mutex); + + /* Count how many methods we have. */ + method_list = class_->methods; + + while (method_list) + { + count = count + method_list->method_count; + method_list = method_list->method_next; + } + + if (count != 0) + { + unsigned int i = 0; + + /* Allocate enough memory to hold them. */ + returnValue + = (struct objc_method **)(malloc (sizeof (struct objc_method *) + * (count + 1))); + + /* Copy the methods. */ + method_list = class_->methods; + + while (method_list) + { + int j; + for (j = 0; j < method_list->method_count; j++) + { + returnValue[i] = &(method_list->method_list[j]); + i++; + } + method_list = method_list->method_next; + } + + returnValue[i] = NULL; + } + + objc_mutex_unlock (__objc_runtime_mutex); + + if (numberOfReturnedMethods) + *numberOfReturnedMethods = count; + + return returnValue; +} diff --git a/libobjc/objc/runtime.h b/libobjc/objc/runtime.h index a52c7611857..a11d283586f 100644 --- a/libobjc/objc/runtime.h +++ b/libobjc/objc/runtime.h @@ -284,16 +284,27 @@ objc_EXPORT id object_getIvar (id object, Ivar variable); object_setInstanceVariable. */ objc_EXPORT void object_setIvar (id object, Ivar variable, id value); -/* Return the name of the instance variable. */ +/* Return the name of the instance variable. Return NULL if + 'variable' is NULL. */ objc_EXPORT const char * ivar_getName (Ivar variable); /* Return the offset of the instance variable from the start of the - object data. */ + object data. Return 0 if 'variable' is NULL. */ objc_EXPORT ptrdiff_t ivar_getOffset (Ivar variable); -/* Return the type encoding of the variable. */ +/* Return the type encoding of the variable. Return NULL if + 'variable' is NULL. */ objc_EXPORT const char * ivar_getTypeEncoding (Ivar variable); +/* Return all the instance variables of the class. The return value + of the function is a pointer to an area, allocated with malloc(), + that contains all the instance variables of the class. It does not + include instance variables of superclasses. The list is terminated + by NULL. Optionally, if you pass a non-NULL + 'numberOfReturnedIvars' pointer, the unsigned int that it points to + will be filled with the number of instance variables returned. */ +objc_EXPORT Ivar * class_copyIvarList (Class class_, unsigned int *numberOfReturnedIvars); + /** Implementation: the following functions are in class.c. */ @@ -412,6 +423,84 @@ objc_EXPORT void class_setVersion (Class class_, int version); objc_EXPORT size_t class_getInstanceSize (Class class_); +/** Implementation: the following functions are in sendmsg.c. */ + +/* Return the instance method with selector 'selector' of class + 'class_', or NULL if the class (or one of its superclasses) does + not implement the method. Return NULL if class_ is Nil or selector + is NULL. */ +objc_EXPORT Method class_getInstanceMethod (Class class_, SEL selector); + +/* Return the class method with selector 'selector' of class 'class_', + or NULL if the class (or one of its superclasses) does not + implement the method. Return NULL if class_ is Nil or selector is + NULL. */ +objc_EXPORT Method class_getClassMethod (Class class_, SEL selector); + +/* Return the IMP (pointer to the function implementing a method) for + the instance method with selector 'selector' in class 'class_'. + This is the same routine that is used while messaging, and should + be very fast. Note that you most likely would need to cast the + return function pointer to a function pointer with the appropriate + arguments and return type before calling it. To get a class + method, you can pass the meta-class as the class_ argument (ie, use + class_getMethodImplementation (object_getClass (class_), + selector)). Return NULL if class_ is Nil or selector is NULL. */ +objc_EXPORT IMP class_getMethodImplementation (Class class_, SEL selector); + +/* Compatibility Note: the Apple/NeXT runtime has the function + class_getMethodImplementation_stret () which currently does not + exist on the GNU runtime because the messaging implementation is + different. */ + +/* Return YES if class 'class_' has an instance method implementing + selector 'selector', and NO if not. Return NO if class_ is Nil or + selector is NULL. If you need to check a class method, use the + meta-class as the class_ argument (ie, use class_respondsToSelector + (object_getClass (class_), selector)). */ +objc_EXPORT BOOL class_respondsToSelector (Class class_, SEL selector); + + +/** Implementation: the following functions are in methods.c. */ + +/* Return the selector for method 'method'. Return NULL if 'method' + is NULL. + + This function is misnamed; it should be called + 'method_getSelector'. To get the actual name, get the selector, + then the name from the selector (ie, use sel_getName + (method_getName (method))). */ +objc_EXPORT SEL method_getName (Method method); + +/* Return the IMP of the method. Return NULL if 'method' is NULL. */ +objc_EXPORT IMP method_getImplementation (Method method); + +/* Return the type encoding of the method. Return NULL if 'method' is + NULL. */ +objc_EXPORT const char * method_getTypeEncoding (Method method); + +/* Return all the instance methods of the class. The return value of + the function is a pointer to an area, allocated with malloc(), that + contains all the instance methods of the class. It does not + include instance methods of superclasses. The list is terminated + by NULL. Optionally, if you pass a non-NULL + 'numberOfReturnedMethods' pointer, the unsigned int that it points + to will be filled with the number of instance methods returned. To + get the list of class methods, pass the meta-class in the 'class_' + argument, (ie, use class_copyMethodList (object_getClass (class_), + &numberOfReturnedMethods)). */ +objc_EXPORT Method * class_copyMethodList (Class class_, unsigned int *numberOfReturnedMethods); + + +/** Implementation: the following functions are in encoding.c. */ + +/* Return the number of arguments that the method 'method' expects. + Note that all methods need two implicit arguments ('self' for the + receiver, and '_cmd' for the selector). Return 0 if 'method' is + NULL. */ +objc_EXPORT unsigned int method_getNumberOfArguments (Method method); + + /** Implementation: the following functions are in protocols.c. */ /* Return the protocol with name 'name', or nil if it the protocol is diff --git a/libobjc/protocols.c b/libobjc/protocols.c index 6d429803c8f..bc714ae63ae 100644 --- a/libobjc/protocols.c +++ b/libobjc/protocols.c @@ -211,6 +211,13 @@ class_copyProtocolList (Class class_, unsigned int *numberOfReturnedProtocols) Protocol **returnValue = NULL; struct objc_protocol_list* proto_list; + if (class_ == Nil) + { + if (numberOfReturnedProtocols) + *numberOfReturnedProtocols = 0; + return NULL; + } + /* Lock the runtime mutex because the class protocols may be concurrently modified. */ objc_mutex_lock (__objc_runtime_mutex); diff --git a/libobjc/sendmsg.c b/libobjc/sendmsg.c index 02be39c5b05..d68e3040f4f 100644 --- a/libobjc/sendmsg.c +++ b/libobjc/sendmsg.c @@ -1,6 +1,6 @@ /* GNU Objective C Runtime message lookup Copyright (C) 1993, 1995, 1996, 1997, 1998, - 2001, 2002, 2004, 2009 Free Software Foundation, Inc. + 2001, 2002, 2004, 2009, 2010 Free Software Foundation, Inc. Contributed by Kresten Krab Thorup This file is part of GCC. @@ -91,8 +91,8 @@ static __big static id #endif __objc_block_forward (id, SEL, ...); -static Method_t search_for_method_in_hierarchy (Class class, SEL sel); -Method_t search_for_method_in_list (MethodList_t list, SEL op); +static struct objc_method * search_for_method_in_hierarchy (Class class, SEL sel); +struct objc_method * search_for_method_in_list (struct objc_method_list * list, SEL op); id nil_method (id, SEL); /* Given a selector, return the proper forwarding implementation. */ @@ -193,11 +193,22 @@ get_imp (Class class, SEL sel) return res; } +/* The new name of get_imp(). */ +IMP +class_getMethodImplementation (Class class_, SEL selector) +{ + if (class_ == Nil || selector == NULL) + return NULL; + + /* get_imp is inlined, so we're good. */ + return get_imp (class_, selector); +} + /* Given a method, return its implementation. */ IMP -method_get_imp (Method_t method) +method_get_imp (struct objc_method * method) { - return (method != (Method_t)0) ? method->method_imp : (IMP)0; + return (method != (struct objc_method *)0) ? method->method_imp : (IMP)0; } /* Query if an object can respond to a selector, returns YES if the @@ -225,6 +236,30 @@ __objc_responds_to (id object, SEL sel) return (res != 0); } +BOOL +class_respondsToSelector (Class class_, SEL selector) +{ + void *res; + + if (class_ == Nil || selector == NULL) + return NO; + + /* Install dispatch table if need be */ + if (class_->dtable == __objc_uninstalled_dtable) + { + objc_mutex_lock (__objc_runtime_mutex); + if (class_->dtable == __objc_uninstalled_dtable) + { + __objc_install_dispatch_table_for_class (class_); + } + objc_mutex_unlock (__objc_runtime_mutex); + } + + /* Get the method from the dispatch table */ + res = sarray_get_safe (class_->dtable, (size_t) selector->sel_id); + return (res != 0); +} + /* This is the lookup function. All entries in the table are either a valid method *or* zero. If zero then either the dispatch table needs to be installed or it doesn't exist and forwarding is attempted. */ @@ -374,11 +409,11 @@ __objc_send_initialize (Class class) { SEL op = sel_register_name ("initialize"); IMP imp = 0; - MethodList_t method_list = class->class_pointer->methods; + struct objc_method_list * method_list = class->class_pointer->methods; while (method_list) { int i; - Method_t method; + struct objc_method * method; for (i = 0; i < method_list->method_count; i++) { method = &(method_list->method_list[i]); @@ -409,7 +444,7 @@ __objc_send_initialize (Class class) method nothing is guaranteed about what method will be used. Assumes that __objc_runtime_mutex is locked down. */ static void -__objc_install_methods_in_dtable (Class class, MethodList_t method_list) +__objc_install_methods_in_dtable (Class class, struct objc_method_list * method_list) { int i; @@ -421,7 +456,7 @@ __objc_install_methods_in_dtable (Class class, MethodList_t method_list) for (i = 0; i < method_list->method_count; i++) { - Method_t method = &(method_list->method_list[i]); + struct objc_method * method = &(method_list->method_list[i]); sarray_at_put_safe (class->dtable, (sidx) method->method_name->sel_id, method->method_imp); @@ -492,7 +527,7 @@ __objc_update_dispatch_table_for_class (Class class) methods installed right away, and their selectors are made into SEL's by the function __objc_register_selectors_from_class. */ void -class_add_method_list (Class class, MethodList_t list) +class_add_method_list (Class class, struct objc_method_list * list) { /* Passing of a linked list is not allowed. Do multiple calls. */ assert (! list->method_next); @@ -507,27 +542,44 @@ class_add_method_list (Class class, MethodList_t list) __objc_update_dispatch_table_for_class (class); } -Method_t +struct objc_method * class_get_instance_method (Class class, SEL op) { return search_for_method_in_hierarchy (class, op); } -Method_t +struct objc_method * class_get_class_method (MetaClass class, SEL op) { return search_for_method_in_hierarchy (class, op); } +struct objc_method * +class_getInstanceMethod (Class class_, SEL selector) +{ + if (class_ == Nil || selector == NULL) + return NULL; + + return search_for_method_in_hierarchy (class_, selector); +} + +struct objc_method * +class_getClassMethod (Class class_, SEL selector) +{ + if (class_ == Nil || selector == NULL) + return NULL; + + return search_for_method_in_hierarchy (class_->class_pointer, + selector); +} /* Search for a method starting from the current class up its hierarchy. Return a pointer to the method's method structure if found. NULL otherwise. */ - -static Method_t +static struct objc_method * search_for_method_in_hierarchy (Class cls, SEL sel) { - Method_t method = NULL; + struct objc_method * method = NULL; Class class; if (! sel_is_mapped (sel)) @@ -546,10 +598,10 @@ search_for_method_in_hierarchy (Class cls, SEL sel) /* Given a linked list of method and a method's name. Search for the named method's method structure. Return a pointer to the method's method structure if found. NULL otherwise. */ -Method_t -search_for_method_in_list (MethodList_t list, SEL op) +struct objc_method * +search_for_method_in_list (struct objc_method_list * list, SEL op) { - MethodList_t method_list = list; + struct objc_method_list * method_list = list; if (! sel_is_mapped (op)) return NULL; @@ -562,7 +614,7 @@ search_for_method_in_list (MethodList_t list, SEL op) /* Search the method list. */ for (i = 0; i < method_list->method_count; ++i) { - Method_t method = &method_list->method_list[i]; + struct objc_method * method = &method_list->method_list[i]; if (method->method_name) if (method->method_name->sel_id == op->sel_id) |