Makefile.in (C_SOURCE_FILES): Added methods.c.

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.

From-SVN: r165400
This commit is contained in:
Nicola Pero 2010-10-12 22:00:01 +00:00 committed by Nicola Pero
parent d761137fee
commit ad9eef11df
8 changed files with 407 additions and 37 deletions

View File

@ -1,3 +1,34 @@
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

View File

@ -173,6 +173,7 @@ C_SOURCE_FILES = \
init.c \
ivars.c \
memory.c \
methods.c \
nil_method.c \
objc-foreach.c \
objc-sync.c \

View File

@ -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'.
*/
unsigned int
method_getNumberOfArguments (struct objc_method *method)
{
if (method == NULL)
return 0;
else
{
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);
}
}
}
int
method_get_number_of_arguments (struct objc_method *mth)
{
int i = 0;
const char *type = mth->method_types;
while (*type)
{
type = objc_skip_argspec (type);
i += 1;
}
return i - 1;
return method_getNumberOfArguments (mth);
}
/*

View File

@ -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;
}

114
libobjc/methods.c Normal file
View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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)