diff mbox

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

Message ID 1286821056.491413870@192.168.2.229
State New
Headers show

Commit Message

Nicola Pero Oct. 11, 2010, 6:17 p.m. UTC
Another patch that adds more meat to objc/runtime.h.  Committed to trunk.

Thanks

PS: We do need testcases for the GNU Objective-C runtime APIs. The existing Objective-C tests currently work nicely as tests for the Traditional GNU Objective-C Runtime API, ie, that I'm not breaking stuff that used to work :-), but they don't test the new API, ie, that the new stuff that I'm adding actually works ;-).  Once I get the bulk done, I'll start writing some tests.

2010-10-11  Nicola Pero  <nicola.pero@meta-innovation.com>

        * class.c (objc_getClassList): New.
        (objc_getRequiredClass): New.
        (objc_getMetaClass): New.
        (objc_lookupClass): New.
        (objc_getClass): New.
        (__objc_get_unknown_class_handler): New.
        (objc_setGetUnknownClassHandler): New.
        (objc_get_class): Use __objc_get_unknown_class_handler.
        (objc_lookup_class): Call objc_getClass.
        * objc/objc-api.h: Updated comment and copyright notice.
        * objc/runtime.h: Updated comments.
        (objc_getClass): New.
        (objc_lookupClass): New.
        (objc_getMetaClass): New.
        (objc_getRequiredClass): New.
        (objc_getClassList): New.
        (objc_setGetUnknownClassHandler): New.
        (objc_get_unknown_class_handler): New.
        * objc-private/runtime.h: Use __objc_private_runtime_INCLUDE_GNU
        instead of __objc_runtime_INCLUDE_GNU as include guard.
        * objc-private/error.h (_objc_abort): Mark as noreturn.
diff mbox

Patch

Index: objc-private/error.h
===================================================================
--- objc-private/error.h	(revision 165248)
+++ objc-private/error.h	(working copy)
@@ -29,9 +29,10 @@  see the files COPYING3 and COPYING.RUNTIME respect
    This should only be used for errors that really are unrecorevable:
    failure to allocate memory, and failure to load an Objective-C
    module.  All other usages of this function should be converted into
-   some milder type of error.
+   some milder type of error (unless aborting is explicitly required
+   by the documentation/API).
 */
 void
-_objc_abort (const char *fmt, ...);
+_objc_abort (const char *fmt, ...) __attribute__ ((noreturn));
 
 #endif /* __objc_private_error_INCLUDE_GNU */
Index: objc-private/runtime.h
===================================================================
--- objc-private/runtime.h	(revision 165248)
+++ objc-private/runtime.h	(working copy)
@@ -36,8 +36,8 @@  but can almost certainly be shrinked down.
 
 */
 
-#ifndef __objc_runtime_INCLUDE_GNU
-#define __objc_runtime_INCLUDE_GNU
+#ifndef __objc_private_runtime_INCLUDE_GNU
+#define __objc_private_runtime_INCLUDE_GNU
 
 #include <stdarg.h>		/* for varargs and va_list's */
 
@@ -98,4 +98,4 @@  extern void __objc_generate_gc_type_description (C
 }
 #endif /* __cplusplus */
 
-#endif /* not __objc_runtime_INCLUDE_GNU */
+#endif /* not __objc_private_runtime_INCLUDE_GNU */
Index: class.c
===================================================================
--- class.c	(revision 165248)
+++ class.c	(working copy)
@@ -408,10 +408,37 @@  class_table_print_histogram (void)
 
 /* This is a hook which is called by objc_get_class and
    objc_lookup_class if the runtime is not able to find the class.  
-   This may e.g. try to load in the class using dynamic loading.  */
+   This may e.g. try to load in the class using dynamic loading.
+
+   This hook was a public, global variable in the Traditional GNU
+   Objective-C Runtime API (objc/objc-api.h).  The modern GNU
+   Objective-C Runtime API (objc/runtime.h) provides the
+   objc_setGetUnknownClassHandler() function instead.
+*/
 Class (*_objc_lookup_class) (const char *name) = 0;      /* !T:SAFE */
 
+/* Temporarily while we still include objc/objc-api.h instead of objc/runtime.h.  */
+#ifndef __objc_runtime_INCLUDE_GNU
+typedef Class (*objc_get_unknown_class_handler)(const char *class_name);
+#endif
 
+/* The handler currently in use.  PS: if both
+   __obj_get_unknown_class_handler and _objc_lookup_class are defined,
+   __objc_get_unknown_class_handler is called first.  */
+static objc_get_unknown_class_handler
+__objc_get_unknown_class_handler = NULL;
+
+objc_get_unknown_class_handler
+objc_setGetUnknownClassHandler (objc_get_unknown_class_handler 
+				new_handler)
+{
+  objc_get_unknown_class_handler old_handler 
+    = __objc_get_unknown_class_handler;
+  __objc_get_unknown_class_handler = new_handler;
+  return old_handler;
+}
+
+
 /* True when class links has been resolved.  */     
 BOOL __objc_class_links_resolved = NO;                  /* !T:UNUSED */
 
@@ -464,27 +491,108 @@  __objc_add_class_to_hash (Class class)
   objc_mutex_unlock (__objc_runtime_mutex);
 }
 
-/* Get the class object for the class named NAME.  If NAME does not
-   identify a known class, the hook _objc_lookup_class is called.  If
-   this fails, nil is returned.  */
 Class
-objc_lookup_class (const char *name)
+objc_getClass (const char *name)
 {
   Class class;
 
+  if (name == NULL)
+    return Nil;
+
   class = class_table_get_safe (name);
-
+  
   if (class)
     return class;
+  
+  if (__objc_get_unknown_class_handler)
+    return (*__objc_get_unknown_class_handler) (name);
 
   if (_objc_lookup_class)
     return (*_objc_lookup_class) (name);
+
+  return Nil;
+}
+
+Class
+objc_lookupClass (const char *name)
+{
+  if (name == NULL)
+    return Nil;
   else
-    return 0;
+    return class_table_get_safe (name);
 }
 
+Class
+objc_getMetaClass (const char *name)
+{
+  Class class = objc_getClass (name);
+
+  if (class)
+    return class->class_pointer;
+  else
+    return Nil;
+}
+
+Class
+objc_getRequiredClass (const char *name)
+{
+  Class class = objc_getClass (name);
+
+  if (class)
+    return class;
+  else
+    _objc_abort ("objc_getRequiredClass ('%s') failed: class not found\n", name);
+}
+
+int
+objc_getClassList (Class *returnValue, int maxNumberOfClassesToReturn)
+{
+  /* Iterate over all entries in the table.  */
+  int hash, count = 0;
+
+  objc_mutex_lock (__class_table_lock); 
+
+  for (hash = 0; hash < CLASS_TABLE_SIZE; hash++)
+    {
+      class_node_ptr node = class_table_array[hash];
+      
+      while (node != NULL)
+	{
+	  if (returnValue)
+	    {
+	      if (count < maxNumberOfClassesToReturn)
+		returnValue[count] = node->pointer;
+	      else
+		{
+		  objc_mutex_unlock (__class_table_lock);
+		  return count;
+		}
+	    }
+	  count++;
+	  node = node->next;
+	}
+    }
+  
+  objc_mutex_unlock (__class_table_lock);
+  return count;
+}
+
+/* Traditional GNU Objective-C Runtime API.  */
 /* Get the class object for the class named NAME.  If NAME does not
    identify a known class, the hook _objc_lookup_class is called.  If
+   this fails, nil is returned.  */
+Class
+objc_lookup_class (const char *name)
+{
+  return objc_getClass (name);
+}
+
+/* Traditional GNU Objective-C Runtime API.  Important: this method is
+   called automatically by the compiler while messaging (if using the
+   traditional ABI), so it is worth keeping it fast; don't make it
+   just a wrapper around objc_getClass().  */
+/* Get the class object for the class named NAME.  If NAME does not
+   identify a known class, the hook _objc_lookup_class is called.  If
    this fails, an error message is issued and the system aborts.  */
 Class
 objc_get_class (const char *name)
@@ -496,13 +604,15 @@  objc_get_class (const char *name)
   if (class)
     return class;
 
-  if (_objc_lookup_class)
+  if (__objc_get_unknown_class_handler)
+    class = (*__objc_get_unknown_class_handler) (name);
+
+  if ((!class)  &&  _objc_lookup_class)
     class = (*_objc_lookup_class) (name);
 
   if (class)
     return class;
   
-  /* FIXME: Should we abort the program here ?  */
   _objc_abort ("objc runtime: cannot find class %s\n", name);
 
   return 0;
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 165269)
+++ ChangeLog	(working copy)
@@ -1,5 +1,29 @@ 
 2010-10-11  Nicola Pero  <nicola.pero@meta-innovation.com>
 
+	* class.c (objc_getClassList): New.
+	(objc_getRequiredClass): New.
+	(objc_getMetaClass): New.
+	(objc_lookupClass): New.
+	(objc_getClass): New.
+	(__objc_get_unknown_class_handler): New.
+	(objc_setGetUnknownClassHandler): New.
+	(objc_get_class): Use __objc_get_unknown_class_handler.
+	(objc_lookup_class): Call objc_getClass.
+	* objc/objc-api.h: Updated comment and copyright notice.
+	* objc/runtime.h: Updated comments.
+	(objc_getClass): New.
+	(objc_lookupClass): New.
+	(objc_getMetaClass): New.
+	(objc_getRequiredClass): New.
+	(objc_getClassList): New.
+	(objc_setGetUnknownClassHandler): New.
+	(objc_get_unknown_class_handler): New.
+	* objc-private/runtime.h: Use __objc_private_runtime_INCLUDE_GNU
+	instead of __objc_runtime_INCLUDE_GNU as include guard.
+	* objc-private/error.h (_objc_abort): Mark as noreturn.
+	
+2010-10-11  Nicola Pero  <nicola.pero@meta-innovation.com>
+
 	* Makefile.in (C_SOURCE_FILES): Added ivars.c.
 	* ivars.c: New.
 	* objc/objc.h: Updated comments.
Index: objc/runtime.h
===================================================================
--- objc/runtime.h	(revision 165269)
+++ objc/runtime.h	(working copy)
@@ -1,4 +1,4 @@ 
-/* GNU Objective-C Runtime API.
+/* GNU Objective-C Runtime API - Modern API
    Copyright (C) 2010 Free Software Foundation, Inc.
    Contributed by Nicola Pero <nicola.pero@meta-innovation.com>
 
@@ -146,14 +146,16 @@  struct objc_method_description
 #define _F_GCINVISIBLE	0x20
 
 
-/** Internals: defined inline.  */
+/** Implementation: the following functions are defined inline.  */
 
 /* Return the class of 'object', or Nil if the object is nil.  If
    'object' is a class, the meta class is returned; if 'object' is a
    meta class, the root meta class is returned (note that this is
    different from the traditional GNU Objective-C Runtime API function
    object_get_class(), which for a meta class would return the meta
-   class itself).  */
+   class itself).  This function is inline, so it is really fast and
+   should be used instead of accessing object->class_pointer
+   directly.  */
 static inline Class
 object_getClass (id object)
 {
@@ -164,7 +166,7 @@  object_getClass (id object)
 }
 
 
-/** Internals: the following functions are in selector.c.  */
+/** Implementation: the following functions are in selector.c.  */
 
 /* Return the name of a given selector.  */
 objc_EXPORT const char *sel_getName (SEL selector);
@@ -198,7 +200,7 @@  objc_EXPORT SEL set_registerTypedName (const char
 objc_EXPORT BOOL sel_isEqual (SEL first_selector, SEL second_selector);
 
 
-/** Internals: the following functions are in objects.c.  */
+/** Implementation: the following functions are in objects.c.  */
 
 /* Create an instance of class 'class_', adding extraBytes to the size
    of the returned object.  This method allocates the appropriate
@@ -228,7 +230,7 @@  objc_EXPORT const char * object_getClassName (id o
 objc_EXPORT Class object_setClass (id object, Class class_);
 
 
-/** Internals: the following functions are in ivars.c.  */
+/** Implementation: the following functions are in ivars.c.  */
 
 /* Return an instance variable given the class and the instance
    variable name.  This is an expensive function to call, so try to
@@ -283,10 +285,81 @@  objc_EXPORT ptrdiff_t ivar_getOffset (Ivar variabl
 objc_EXPORT const char * ivar_getTypeEncoding (Ivar variable);
 
 
+/** Implementation: the following functions are in class.c.  */
+
+/* Compatibility Note: The Apple/NeXT runtime does not have
+   objc_get_unknown_class_handler and
+   objc_setGetUnknownClassHandler().  They provide functionality that
+   the traditional GNU Objective-C Runtime API used to provide via the
+   _objc_lookup_class hook.  */
+
+/* An 'objc_get_unknown_class_handler' function is used by
+   objc_getClass() to get a class that is currently unknown to the
+   compiler.  You could use it for example to have the class loaded by
+   dynamically loading a library.  'class_name' is the name of the
+   class.  The function should return the Class object if it manages to
+   load the class, and Nil if not.  */
+typedef Class (*objc_get_unknown_class_handler)(const char *class_name);
+
+/* Sets a new handler function for getting unknown classes (to be used
+   by objc_getClass () and related), and returns the previous one.
+   This function is not safe to call in a multi-threaded environment
+   because other threads may be trying to use the get unknown class
+   handler while you change it!  */
+objc_get_unknown_class_handler
+objc_setGetUnknownClassHandler (objc_get_unknown_class_handler new_handler);
+
+
+/* Return the class with name 'name', if it is already registered with
+   the runtime.  If it is not registered, and
+   objc_setGetUnknownClassHandler() has been called to set a handler
+   for unknown classes, the handler is called to give it a chance to
+   load the class in some other way.  If the class is not known to the
+   runtime and the handler is not set or returns Nil, objc_getClass()
+   returns Nil.  */
+objc_EXPORT Class objc_getClass (const char *name);
+
+/* Return the class with name 'name', if it is already registered with
+   the runtime.  Return Nil if not.  This function does not call the
+   objc_get_unknown_class_handler function if the class is not
+   found.  */
+objc_EXPORT Class objc_lookupClass (const char *name);
+
+/* Return the meta class associated to the class with name 'name', if
+   it is already registered with the runtime.  First, it finds the
+   class using objc_getClass().  Then, it returns the associated meta
+   class.  If the class could not be found using objc_getClass(),
+   returns Nil.  */
+objc_EXPORT Class objc_getMetaClass (const char *name);
+
+/* This is identical to objc_getClass(), but if the class is not found,
+   it aborts the process instead of returning Nil.  */
+objc_EXPORT Class objc_getRequiredClass (const char *name);
+
+/* If 'returnValue' is NULL, 'objc_getClassList' returns the number of
+   classes currently registered with the runtime.  If 'returnValue' is
+   not NULL, it should be a (Class *) pointer to an area of memory
+   which can contain up to 'maxNumberOfClassesToReturn' Class records.
+   'objc_getClassList' will fill the area pointed to by 'returnValue'
+   with all the Classes registered with the runtime (or up to
+   maxNumberOfClassesToReturn if there are more than
+   maxNumberOfClassesToReturn).  The function return value is the
+   number of classes actually returned in 'returnValue'.  */
+objc_EXPORT int objc_getClassList (Class *returnValue, int maxNumberOfClassesToReturn); 
+
+/* Compatibility Note: The Apple/NeXT runtime also has
+
+    Class objc_getFutureClass (const char *name);
+    void objc_setFutureClass (Class class_, const char *name);
+
+   the documentation is unclear on what they are supposed to do, and
+   the GNU Objective-C Runtime currently does not provide them.  */
+
+
 /* TODO: Add all the other functions in the API.  */
 
 
-/** Internals: the following functions are in objc-foreach.c.  */
+/** Implementation: the following functions are in objc-foreach.c.  */
 
 /* 'objc_enumerationMutation()' is called when a collection is
    mutated while being "fast enumerated".  That is a hard error, and
@@ -337,7 +410,7 @@  struct __objcFastEnumerationState
 */
 
 
-/** Internals: the following functions are implemented in encoding.c.  */
+/** Implementation: the following functions are in encoding.c.  */
 
 /* Traditional GNU Objective-C Runtime functions that are currently
    used to implement method forwarding.
Index: objc/objc-api.h
===================================================================
--- objc/objc-api.h	(revision 165264)
+++ objc/objc-api.h	(working copy)
@@ -1,6 +1,6 @@ 
-/* GNU Objective-C Runtime API.
+/* GNU Objective-C Runtime API - Traditional API
    Copyright (C) 1993, 1995, 1996, 1997, 2001, 2002, 2003, 2004, 2005,
-   2007, 2009 Free Software Foundation, Inc.
+   2007, 2009, 2010 Free Software Foundation, Inc.
 
 This file is part of GCC.