diff mbox

=?UTF-8?Q?libobjc=20-=20more=20modern=20Objective-C=20runtime=20API=20(5?= =?UTF-8?Q?)=20?=

Message ID 1286920901.692114680@192.168.2.228
State New
Headers show

Commit Message

Nicola Pero Oct. 12, 2010, 10:01 p.m. UTC
Another chunk of "modern" runtime functions.  Committed to trunk.

Thanks

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.
diff mbox

Patch

Index: sendmsg.c
===================================================================
--- sendmsg.c	(revision 165396)
+++ sendmsg.c	(working copy)
@@ -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 @@  static void
 
   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 clas
    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 @@  void
   __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_hierarchy (Class cls, SEL sel
       /* 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)
Index: Makefile.in
===================================================================
--- Makefile.in	(revision 165396)
+++ Makefile.in	(working copy)
@@ -173,6 +173,7 @@  C_SOURCE_FILES = \
    init.c \
    ivars.c \
    memory.c \
+   methods.c \
    nil_method.c \
    objc-foreach.c \
    objc-sync.c \
Index: protocols.c
===================================================================
--- protocols.c	(revision 165396)
+++ protocols.c	(working copy)
@@ -211,6 +211,13 @@  class_copyProtocolList (Class class_, unsigned int
   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);
Index: encoding.c
===================================================================
--- encoding.c	(revision 165396)
+++ encoding.c	(working copy)
@@ -797,24 +797,41 @@  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);
+}
+
 /*
   Return the size of the argument block needed on the stack to invoke
   the method MTH.  This may be zero, if all arguments are passed in
Index: methods.c
===================================================================
--- methods.c	(revision 0)
+++ methods.c	(revision 0)
@@ -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;
+}
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 165396)
+++ ChangeLog	(working copy)
@@ -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.
Index: ivars.c
===================================================================
--- ivars.c	(revision 165396)
+++ ivars.c	(working copy)
@@ -26,8 +26,8 @@  see the files COPYING3 and COPYING.RUNTIME respect
 #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 *
 
 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;
+}
Index: objc/runtime.h
===================================================================
--- objc/runtime.h	(revision 165396)
+++ objc/runtime.h	(working copy)
@@ -284,17 +284,28 @@  objc_EXPORT id object_getIvar (id object, Ivar var
    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.  */
 
 /* Compatibility Note: The Apple/NeXT runtime does not have
@@ -412,6 +423,84 @@  objc_EXPORT void class_setVersion (Class class_, i
 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