In gcc/: 2010-10-17 Nicola Pero <nicola.pero@meta-innovation.com>

In gcc/:
2010-10-17  Nicola Pero  <nicola.pero@meta-innovation.com>

        * doc/objc.texi (GNU Objective-C runtime API): New section.
        (Modern GNU Objective-C runtime API): New section.
        (Traditional GNU Objective-C runtime API): New section.
        (Executing code before main): Mention that this section is
        specific to the GNU Objective-C runtime.
        (Garbage Collection): Same.

In gcc/testsuite/:
2010-10-17  Nicola Pero  <nicola.pero@meta-innovation.com>

        * obj-c++.dg/gnu-api-2-class.mm: New.
        * obj-c++.dg/gnu-api-2-ivar.mm: New.
        * obj-c++.dg/gnu-api-2-method.mm: New.
        * obj-c++.dg/gnu-api-2-objc.mm: New.
        * obj-c++.dg/gnu-api-2-object.mm: New.
        * obj-c++.dg/gnu-api-2-property.mm: New.
        * obj-c++.dg/gnu-api-2-protocol.mm: New.
        * obj-c++.dg/gnu-api-2-sel.mm: New.


In libobjc/:
2010-10-17  Nicola Pero  <nicola.pero@meta-innovation.com>

        * objc/message.h: Moved initial includes outside of extern "C".
        * objc/runtime.h: Add extern "C" for Objective-C++.

From-SVN: r165595
This commit is contained in:
Nicola Pero 2010-10-17 19:33:19 +00:00 committed by Nicola Pero
parent 91b90ead33
commit 5b8b526e69
14 changed files with 1636 additions and 5 deletions

View File

@ -1,3 +1,12 @@
2010-10-17 Nicola Pero <nicola.pero@meta-innovation.com>
* doc/objc.texi (GNU Objective-C runtime API): New section.
(Modern GNU Objective-C runtime API): New section.
(Traditional GNU Objective-C runtime API): New section.
(Executing code before main): Mention that this section is
specific to the GNU Objective-C runtime.
(Garbage Collection): Same.
2010-10-17 Uros Bizjak <ubizjak@gmail.com>
* c-parser.c (c_parser_for_statement): Move initialization of

View File

@ -9,10 +9,11 @@
@chapter GNU Objective-C features
This document is meant to describe some of the GNU Objective-C
features. It is not intended to teach you Objective-C, there are
features. It is not intended to teach you Objective-C. There are
several resources on the Internet that present the language.
@menu
* GNU Objective-C runtime API::
* Executing code before main::
* Type encoding::
* Garbage Collection::
@ -23,9 +24,124 @@ several resources on the Internet that present the language.
* Fast enumeration::
@end menu
@c =========================================================================
@node GNU Objective-C runtime API
@section GNU Objective-C runtime API
This section is specific for the GNU Objective-C runtime. If you are
using a different runtime, you can skip it.
The GNU Objective-C runtime provides an API that allows you to
interact with the Objective-C runtime system, querying the live
runtime structures and even manipulating them. This allows you for
example to inspect and navigate classes, methods and protocols; to
define new classes or new methods, and even to modify existing classes
or protocols.
If you are using a ``Foundation'' library such as GNUstep-Base, this
library will provide you with a rich set of functionality to do most
of the inspection tasks, and you probably will only need direct access
to the GNU Objective-C runtime API to define new classes or methods.
@menu
* Modern GNU Objective-C runtime API::
* Traditional GNU Objective-C runtime API::
@end menu
@c =========================================================================
@node Modern GNU Objective-C runtime API
@subsection Modern GNU Objective-C runtime API
The GNU Objective-C runtime provides an API which is similar to the
one provided by the ``Objective-C 2.0'' Apple/NeXT Objective-C
runtime. The API is documented in the public header files of the GNU
Objective-C runtime:
@itemize @bullet
@item
@file{objc/objc.h}: this is the basic Objective-C header file,
defining the basic Objective-C types such as @code{id}, @code{Class}
and @code{BOOL}. You have to include this header to do almost
anything with Objective-C.
@item
@file{objc/runtime.h}: this header declares most of the public runtime
API functions allowing you to inspect and manipulate the Objective-C
runtime data structures. These functions are fairly standardized
across Objective-C runtimes and are almost identical to the Apple/NeXT
Objective-C runtime ones. It does not declare functions in some
specialized areas (constructing and forwarding message invocations,
threading) which are in the other headers below. You have to include
@file{objc/objc.h} and @file{objc/runtime.h} to use any of the
functions, such as @code{class_getName()}, declared in
@file{objc/runtime.h}.
@item
@file{objc/message.h}: this header declares public functions used to
construct, deconstruct and forward message invocations. Because
messaging is done in quite a different way on different runtimes,
functions in this header are specific to the GNU Objective-C runtime
implementation.
@item
@file{objc/objc-exception.h}: this header declares some public
functions related to Objective-C exceptions. For example functions in
this header allow you to throw an Objective-C exception from plain
C/C++ code.
@item
@file{objc/objc-sync.h}: this header declares some public functions
related to the Objective-C @code{@@synchronized()} syntax, allowing
you to emulate an Objective-C @code{@@synchronized()} block in plain
C/C++ code.
@item
@file{objc/thr.h}: this header declares a public runtime API threading
layer that is only provided by the GNU Objective-C runtime. It
declares functions such as @code{objc_mutex_lock()}, which provide a
platform-independent set of threading functions.
@end itemize
@c =========================================================================
@node Traditional GNU Objective-C runtime API
@subsection Traditional GNU Objective-C runtime API
The GNU Objective-C runtime used to provide a different API, which we
call the ``traditional'' GNU Objective-C runtime API. Functions
belonging to this API are easy to recognize because they use a
different naming convention, such as @code{class_get_super_class()}
(traditional API) instead of @code{class_getSuperclass()} (modern
API). Software using this API includes the file
@file{objc/objc-api.h} where it is declared.
The traditional API is deprecated but it is still supported in this
release of the runtime; you can access it as usual by including
@file{objc/objc-api.h}.
If you are using the traditional API you are urged to upgrade your
software to use the modern API because the traditional API requires
access to private runtime internals to do anything serious with it;
for this reason, there is no guarantee that future releases of the GNU
Objective-C runtime library will be able to provide a fully compatible
@file{objc/objc-api.h} as the private runtime internals change. It is
expected that the next release will hide a number of runtime internals
making the traditional API nominally supported but fairly useless
beyond very simple use cases.
Finally, you can not include both @file{objc/objc-api.h} and
@file{objc/runtime.h} at the same time. The traditional and modern
APIs unfortunately have some conflicting declarations (such as the one
for @code{Method}) and can not be used at the same time.
@c =========================================================================
@node Executing code before main
@section @code{+load}: Executing code before main
This section is specific for the GNU Objective-C runtime. If you are
using a different runtime, you can skip it.
The GNU Objective-C runtime provides a way that allows you to execute
code before the execution of the program enters the @code{main}
function. The code is executed on a per-class and a per-category basis,
@ -480,6 +596,9 @@ of Objective-C methods.
@node Garbage Collection
@section Garbage Collection
This section is specific for the GNU Objective-C runtime. If you are
using a different runtime, you can skip it.
Support for garbage collection with the GNU runtime has been added by
using a powerful conservative garbage collector, known as the
Boehm-Demers-Weiser conservative garbage collector.

View File

@ -1,3 +1,14 @@
2010-10-17 Nicola Pero <nicola.pero@meta-innovation.com>
* obj-c++.dg/gnu-api-2-class.mm: New.
* obj-c++.dg/gnu-api-2-ivar.mm: New.
* obj-c++.dg/gnu-api-2-method.mm: New.
* obj-c++.dg/gnu-api-2-objc.mm: New.
* obj-c++.dg/gnu-api-2-object.mm: New.
* obj-c++.dg/gnu-api-2-property.mm: New.
* obj-c++.dg/gnu-api-2-protocol.mm: New.
* obj-c++.dg/gnu-api-2-sel.mm: New.
2010-10-17 Iain Sandoe <iains@gcc.gnu.org>
* objc.dg/fsf-package-0.m: New.

View File

@ -0,0 +1,441 @@
/* Test the Modern GNU Objective-C Runtime API.
This is test 'class', covering all functions starting with 'class'. */
/* { dg-do run } */
/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */
/* To get the modern GNU Objective-C Runtime API, you include
objc/runtime.h. */
#include <objc/runtime.h>
#include <stdlib.h>
#include <iostream>
#include <cstring>
@interface MyRootClass
{ Class isa; }
+ alloc;
- init;
@end
@implementation MyRootClass
+ alloc { return class_createInstance (self, 0); }
- init { return self; }
@end
@protocol MyProtocol
- (id) variable;
@end
@protocol MySecondProtocol
- (id) setVariable: (id)value;
@end
@interface MySubClass : MyRootClass <MyProtocol>
{ id variable_ivar; }
- (void) setVariable: (id)value;
- (id) variable;
@end
@implementation MySubClass
- (void) setVariable: (id)value { variable_ivar = value; }
- (id) variable { return variable_ivar; }
@end
@interface DifferentClass : MyRootClass
- (id) myClass;
- (id) self;
@end
@implementation DifferentClass
- (id) myClass { return object_getClass (self); }
- (id) self { return self; }
@end
@interface MySubClass (MySelf)
- (id) mySelf;
@end
int main ()
{
/* Functions are tested in alphabetical order. */
std::cout << "Testing class_addIvar ()...\n";
{
Class new_class = objc_allocateClassPair (objc_getClass ("MySubClass"), "MySubSubClass", 0);
if (new_class == Nil)
abort ();
if (! class_addIvar (new_class, "variable2_ivar", sizeof (id),
__alignof__ (id), @encode (id)))
abort ();
if (! class_addIvar (new_class, "variable3_ivar", sizeof (unsigned char),
__alignof__ (unsigned char), @encode (unsigned char)))
abort ();
if (! class_addIvar (new_class, "variable4_ivar", sizeof (unsigned long),
__alignof__ (unsigned long), @encode (unsigned long)))
abort ();
objc_registerClassPair (new_class);
{
MySubClass *o = [[objc_getClass ("MySubSubClass") alloc] init];
Ivar variable2 = class_getInstanceVariable (objc_getClass ("MySubSubClass"), "variable2_ivar");
Ivar variable3 = class_getInstanceVariable (objc_getClass ("MySubSubClass"), "variable3_ivar");
Ivar variable4 = class_getInstanceVariable (objc_getClass ("MySubSubClass"), "variable4_ivar");
if (variable2 == NULL || variable3 == NULL || variable4 == NULL)
abort ();
if (std::strcmp (ivar_getName (variable2), "variable2_ivar") != 0)
abort ();
if (std::strcmp (ivar_getName (variable3), "variable3_ivar") != 0)
abort ();
if (std::strcmp (ivar_getName (variable4), "variable4_ivar") != 0)
abort ();
{
unsigned char *var3 = (unsigned char *)((char *)o + ivar_getOffset (variable3));
unsigned long *var4 = (unsigned long *)((char *)o + ivar_getOffset (variable4));
object_setIvar (o, variable2, new_class);
*var3 = 230;
*var4 = 89000L;
if (object_getIvar (o, variable2) != new_class)
abort ();
if (*var3 != 230)
abort ();
if (*var4 != 89000L)
abort ();
}
}
}
std::cout << "Testing class_addMethod ()...\n";
{
Class new_class = objc_allocateClassPair (objc_getClass ("MyRootClass"), "MySubClass2", 0);
Method method1 = class_getInstanceMethod (objc_getClass ("MySubClass"), @selector (setVariable:));
Method method2 = class_getInstanceMethod (objc_getClass ("MySubClass"), @selector (variable));
if (new_class == Nil)
abort ();
if (! class_addIvar (new_class, "variable_ivar", sizeof (id),
__alignof__ (id), @encode (id)))
abort ();
if (! class_addMethod (new_class, @selector (setVariable:), method_getImplementation (method1),
method_getTypeEncoding (method1)))
abort ();
if (! class_addMethod (new_class, @selector (variable), method_getImplementation (method2),
method_getTypeEncoding (method2)))
abort ();
objc_registerClassPair (new_class);
/* Now, MySubClass2 is basically the same as MySubClass! We'll
use the variable and setVariable: methods on it. */
{
MySubClass *o = (MySubClass *)[[objc_getClass ("MySubClass2") alloc] init];
[o setVariable: o];
if ([o variable] != o)
abort ();
}
}
std::cout << "Testing class_addProtocol ()...\n";
{
if (!class_addProtocol (objc_getClass ("MySubClass"), @protocol (MySecondProtocol)))
abort ();
if (!class_conformsToProtocol (objc_getClass ("MySubClass"), @protocol (MyProtocol)))
abort ();
if (!class_conformsToProtocol (objc_getClass ("MySubClass"), @protocol (MySecondProtocol)))
abort ();
}
std::cout << "Testing class_conformsToProtocol ()...\n";
{
if (class_conformsToProtocol (objc_getClass ("MyRootClass"), @protocol (MyProtocol)))
abort ();
if (!class_conformsToProtocol (objc_getClass ("MySubClass"), @protocol (MyProtocol)))
abort ();
}
std::cout << "Testing class_copyIvarList ()...\n";
{
unsigned int count;
Ivar * list = class_copyIvarList (objc_getClass ("MySubClass"), &count);
if (count != 1)
abort ();
if (std::strcmp (ivar_getName (list[0]), "variable_ivar") != 0)
abort ();
if (list[1] != NULL)
abort ();
}
std::cout << "Testing class_copyMethodList ()...\n";
{
unsigned int count;
Method * list = class_copyMethodList (objc_getClass ("MySubClass"), &count);
if (count != 2)
abort ();
if (! ((std::strcmp (sel_getName (method_getName (list[0])), "variable") == 0
&& std::strcmp (sel_getName (method_getName (list[1])), "setVariable:") == 0)
|| (std::strcmp (sel_getName (method_getName (list[0])), "setVariable:") == 0
&& std::strcmp (sel_getName (method_getName (list[1])), "variable") == 0)))
abort ();
if (list[2] != NULL)
abort ();
}
/* TODO: Test new ABI (when available). */
std::cout << "Testing class_copyPropertyList ()...\n";
{
unsigned int count;
Property * list = class_copyPropertyList (objc_getClass ("MySubClass"), &count);
if (count != 0 || list != NULL)
abort ();
}
std::cout << "Testing class_copyProtocolList ()...\n";
{
unsigned int count;
Protocol ** list = class_copyProtocolList (objc_getClass ("MySubClass"), &count);
/* Remember that we added MySecondProtocol in the test above. */
if (count != 2)
abort ();
if (! ((std::strcmp (protocol_getName (list[0]), "MyProtocol") == 0
&& std::strcmp (protocol_getName (list[1]), "MySecondProtocol") == 0)
|| (std::strcmp (protocol_getName (list[0]), "MySecondProtocol") == 0
&& std::strcmp (protocol_getName (list[1]), "MyProtocol") == 0)))
abort ();
if (list[2] != NULL)
abort ();
}
std::cout << "Testing class_createInstance ()...\n";
{
MySubClass *object = [[MySubClass alloc] init];
[object setVariable: object];
if ([object variable] != object)
abort ();
}
std::cout << "Testing class_getClassMethod ()...\n";
{
Method method = class_getClassMethod (objc_getClass ("MySubClass"),
@selector(alloc));
if (method == NULL)
abort ();
if (std::strcmp (sel_getName (method_getName (method)), "alloc") != 0)
abort ();
if (class_getClassMethod (objc_getClass ("MySubClass"),
@selector(variable)))
abort ();
}
std::cout << "Testing class_getClassVariable ()...\n";
{
if (class_getClassVariable (objc_getClass ("MySubClass"), "variable_ivar"))
abort ();
}
std::cout << "Testing class_getInstanceMethod ()...\n";
{
Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
@selector(variable));
if (method == NULL)
abort ();
if (std::strcmp (sel_getName (method_getName (method)), "variable") != 0)
abort ();
if (class_getInstanceMethod (objc_getClass ("MySubClass"),
@selector(alloc)))
abort ();
}
std::cout << "Testing class_getInstanceSize ()...\n";
{
if (class_getInstanceSize (objc_getClass ("MyRootClass")) != sizeof (struct objc_object))
abort ();
}
std::cout << "Testing class_getInstanceVariable ()...\n";
{
Ivar variable = class_getInstanceVariable (objc_getClass ("MySubClass"), "variable_ivar");
if (variable == NULL)
abort ();
if (std::strcmp (ivar_getName (variable), "variable_ivar") != 0)
abort ();
if (class_getInstanceVariable (objc_getClass ("MySubClass"), "variable_ivar_no"))
abort ();
}
std::cout << "Testing class_getIvarLayout ()...\n";
{
if (class_getIvarLayout (objc_getClass ("MyRootClass")) != NULL)
abort ();
}
std::cout << "Testing class_getMethodImplementation ()...\n";
{
MySubClass *object = [[MySubClass alloc] init];
IMP imp = class_getMethodImplementation (objc_getClass ("MySubClass"),
@selector(variable));
if (imp == NULL)
abort ();
[object setVariable: object];
if ((*imp)(object, @selector(variable)) != object)
abort ();
}
/* This function does not exist with the GNU runtime. */
/* std::cout << "Testing class_getMethodImplementation_stret ()...\n"; */
std::cout << "Testing class_getName ()...\n";
{
if (std::strcmp (class_getName (objc_getClass ("MyRootClass")),
"MyRootClass") != 0)
abort ();
}
/* TODO: Test new ABI (when available). */
std::cout << "Testing class_getProperty ()...\n";
{
if (class_getProperty (objc_getClass ("MyRootClass"), "property") != NULL)
abort ();
}
std::cout << "Testing class_getSuperclass ()...\n";
{
MySubClass *object = [[MySubClass alloc] init];
if (class_getSuperclass (object_getClass (object)) != objc_getClass ("MyRootClass"))
abort ();
}
std::cout << "Testing class_getVersion ()...\n";
{
if (class_getVersion (objc_getClass ("MySubClass")) != 0)
abort ();
}
std::cout << "Testing class_getWeakIvarLayout ()...\n";
{
if (class_getWeakIvarLayout (objc_getClass ("MyRootClass")) != NULL)
abort ();
}
std::cout << "Testing class_isMetaClass ()...\n";
{
MySubClass *object = [[MySubClass alloc] init];
if (class_isMetaClass (object_getClass (object))
|| ! class_isMetaClass (object_getClass (object_getClass (object))))
abort ();
}
std::cout << "Testing class_replaceMethod ()...\n";
{
Method new_method = class_getInstanceMethod (objc_getClass ("DifferentClass"),
@selector (myClass));
Method old_method = class_getInstanceMethod (objc_getClass ("MySubClass"),
@selector (variable));
const char *new_types = method_getTypeEncoding (new_method);
IMP new_imp = method_getImplementation (new_method);
const char *old_types = method_getTypeEncoding (old_method);
IMP old_imp = class_replaceMethod (objc_getClass ("MySubClass"), @selector (variable),
method_getImplementation (new_method),
method_getTypeEncoding (new_method));
MySubClass *o = [[MySubClass alloc] init];
[o setVariable: o];
/* Try the new method implementation. */
if ([o variable] != objc_getClass ("MySubClass"))
abort ();
/* Put the original method back. */
class_replaceMethod (objc_getClass ("MySubClass"), @selector (variable),
old_imp, old_types);
/* Test it's back to what it was. */
if ([o variable] != o)
abort ();
{
DifferentClass *o = [[DifferentClass alloc] init];
/* Finally, try adding a new method. */
class_replaceMethod (objc_getClass ("DifferentClass"), @selector (mySelf),
new_imp, new_types);
if ([(MySubClass*)o mySelf] != objc_getClass ("DifferentClass"))
abort ();
}
}
std::cout << "Testing class_respondsToSelector ()...\n";
{
if (! class_respondsToSelector (objc_getClass ("MySubClass"), @selector(setVariable:)))
abort ();
if (class_respondsToSelector (objc_getClass ("MyRootClass"), @selector(setVariable:)))
abort ();
}
/* This is not really implemented with the GNU runtime. */
/* std::cout << "Testing class_setIvarLayout ()...\n"; */
std::cout << "Testing class_setVersion ()...\n";
{
class_setVersion (objc_getClass ("MySubClass"), 45);
if (class_getVersion (objc_getClass ("MySubClass")) != 45)
abort ();
class_setVersion (objc_getClass ("MySubClass"), 46);
if (class_getVersion (objc_getClass ("MySubClass")) != 46)
abort ();
}
/* This is not really implemented with the GNU runtime. */
/* std::cout << "Testing class_setWeakIvarLayout ()...\n"; */
return (0);
}

View File

@ -0,0 +1,80 @@
/* Test the Modern GNU Objective-C Runtime API.
This is test 'ivar', covering all functions starting with 'ivar'. */
/* { dg-do run } */
/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */
/* To get the modern GNU Objective-C Runtime API, you include
objc/runtime.h. */
#include <objc/runtime.h>
#include <stdlib.h>
#include <iostream>
#include <cstring>
@interface MyRootClass
{ Class isa; }
+ alloc;
- init;
@end
@implementation MyRootClass
+ alloc { return class_createInstance (self, 0); }
- init { return self; }
@end
@protocol MyProtocol
- (id) variable;
@end
@protocol MySecondProtocol
- (id) setVariable: (id)value;
@end
@interface MySubClass : MyRootClass <MyProtocol>
{ id variable_ivar; }
- (void) setVariable: (id)value;
- (id) variable;
@end
@implementation MySubClass
- (void) setVariable: (id)value { variable_ivar = value; }
- (id) variable { return variable_ivar; }
@end
int main ()
{
/* Functions are tested in alphabetical order. */
std::cout << "Testing ivar_getName () ...\n";
{
Ivar ivar = class_getInstanceVariable (objc_getClass ("MySubClass"),
"variable_ivar");
if (strcmp (ivar_getName (ivar), "variable_ivar") != 0)
abort ();
ivar = class_getInstanceVariable (objc_getClass ("MySubClass"),
"variable");
if (ivar != 0)
abort ();
}
std::cout << "Testing ivar_getOffset () ...\n";
{
Ivar ivar = class_getInstanceVariable (objc_getClass ("MyRootClass"),
"isa");
if (ivar_getOffset (ivar) != 0)
abort ();
}
std::cout << "Testing ivar_getTypeEncoding () ...\n";
{
Ivar ivar = class_getInstanceVariable (objc_getClass ("MySubClass"),
"variable_ivar");
if (strcmp (ivar_getTypeEncoding (ivar), "@") != 0)
abort ();
}
return (0);
}

View File

@ -0,0 +1,227 @@
/* Test the Modern GNU Objective-C Runtime API.
This is test 'method', covering all functions starting with 'method'. */
/* { dg-do run } */
/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */
/* To get the modern GNU Objective-C Runtime API, you include
objc/runtime.h. */
#include <objc/runtime.h>
#include <stdlib.h>
#include <iostream>
#include <cstring>
@interface MyRootClass
{ Class isa; }
+ alloc;
- init;
@end
@implementation MyRootClass
+ alloc { return class_createInstance (self, 0); }
- init { return self; }
@end
@protocol MyProtocol
- (id) variable;
@end
@protocol MySecondProtocol
- (id) setVariable: (id)value;
@end
@interface MySubClass : MyRootClass <MyProtocol>
{ id variable_ivar; }
- (void) setVariable: (id)value;
- (id) variable;
- (id) constant;
@end
@implementation MySubClass
- (void) setVariable: (id)value { variable_ivar = value; }
- (id) variable { return variable_ivar; }
- (id) constant { return nil; }
@end
int main ()
{
/* Functions are tested in alphabetical order. */
std::cout <<"Testing method_copyArgumentType () ...\n";
{
Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
@selector (setVariable:));
char *type = method_copyArgumentType (method, 2);
if (type == NULL || type[0] != '@')
abort ();
}
std::cout << "Testing method_copyReturnType () ...\n";
{
Method method = class_getClassMethod (objc_getClass ("MyRootClass"),
@selector (alloc));
char *type = method_copyReturnType (method);
/* Check that it returns an object. */
if (type == NULL || type[0] != '@')
abort ();
}
std::cout << "Testing method_exchangeImplementations () ...\n";
{
Method method_a = class_getInstanceMethod (objc_getClass ("MySubClass"),
@selector (variable));
Method method_b = class_getInstanceMethod (objc_getClass ("MySubClass"),
@selector (constant));
MySubClass *object = [[MySubClass alloc] init];
/* Check that things work as expected before the swap. */
[object setVariable: object];
if ([object variable] != object || [object constant] != nil)
abort ();
/* Swap the methods. */
method_exchangeImplementations (method_a, method_b);
/* Check that behaviour has changed. */
if ([object variable] != nil || [object constant] != object)
abort ();
/* Swap the methods again. */
method_exchangeImplementations (method_a, method_b);
/* Check that behaviour is back to normal. */
if ([object variable] != object || [object constant] != nil)
abort ();
}
std::cout << "Testing method_getArgumentType () ...\n";
{
Method method = class_getInstanceMethod (objc_getClass ("MyRootClass"),
@selector (init));
char type[16];
method_getArgumentType (method, 1, type, 16);
/* Check the second argument (_cmd), which should be a SEL. */
if (type[0] != ':')
abort ();
}
std::cout << "Testing method_getDescription () ...\n";
{
Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
@selector (variable));
struct objc_method_description *description = method_getDescription (method);
if (std::strcmp (sel_getName (description->name), "variable") != 0)
abort ();
if (method_getDescription (NULL) != NULL)
abort ();
}
std::cout << "Testing method_getImplementation () ...\n";
{
typedef void (*set_variable_function) (id receiver, SEL _cmd, id variable);
Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
@selector (setVariable:));
set_variable_function imp;
MySubClass *object = [[MySubClass alloc] init];
imp = (set_variable_function)(method_getImplementation (method));
(*imp)(object, @selector (setVariable:), object);
if ([object variable] != object)
abort ();
}
std::cout << "Testing method_getName () ...\n";
{
Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
@selector (setVariable:));
if (std::strcmp (sel_getName (method_getName (method)), "setVariable:") != 0)
abort ();
}
std::cout << "Testing method_getNumberOfArguments () ...\n";
{
Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
@selector (setVariable:));
if (method_getNumberOfArguments (method) != 3)
abort ();
method = class_getInstanceMethod (objc_getClass ("MySubClass"),
@selector (variable));
if (method_getNumberOfArguments (method) != 2)
abort ();
}
std::cout << "Testing method_getTypeEncoding () ...\n";
{
Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
@selector (setVariable:));
const char *types = method_getTypeEncoding (method);
/* Check that method type string starts with 'v' (void) */
if (types == NULL || types[0] != 'v')
abort ();
}
std::cout << "Testing method_getReturnType () ...\n";
{
Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
@selector (setVariable:));
char type[16];
method_getReturnType (method, type, 16);
if (type[0] != 'v')
abort ();
method_getReturnType (NULL, type, 16);
if (type[0] != 0)
abort ();
}
std::cout << "Testing method_setImplementation () ...\n";
{
Method method_a = class_getInstanceMethod (objc_getClass ("MySubClass"),
@selector (variable));
Method method_b = class_getInstanceMethod (objc_getClass ("MySubClass"),
@selector (constant));
IMP original_imp_a = method_getImplementation (method_a);
IMP original_imp_b = method_getImplementation (method_b);
MySubClass *object = [[MySubClass alloc] init];
/* Check that things work as expected before the swap. */
[object setVariable: object];
if ([object variable] != object || [object constant] != nil)
abort ();
/* Have 'variable' use the same implementation as 'constant'. */
if (method_setImplementation (method_a, original_imp_b) != original_imp_a)
abort ();
/* Check that behaviour has changed. */
if ([object variable] != nil || [object constant] != nil)
abort ();
/* Put the original method back. */
if (method_setImplementation (method_a, original_imp_a) != original_imp_b)
abort ();
/* Check that behaviour is back to normal. */
if ([object variable] != object || [object constant] != nil)
abort ();
}
return (0);
}

View File

@ -0,0 +1,242 @@
/* Test the Modern GNU Objective-C Runtime API.
This is test 'objc', covering all functions starting with 'objc'. */
/* { dg-do run } */
/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */
/* To get the modern GNU Objective-C Runtime API, you include
objc/runtime.h. */
#include <objc/runtime.h>
#include <stdlib.h>
#include <iostream>
#include <cstring>
@interface MyRootClass
{ Class isa; }
+ alloc;
- init;
@end
@implementation MyRootClass
+ alloc { return class_createInstance (self, 0); }
- init { return self; }
@end
@protocol MyProtocol
- (id) variable;
@end
@protocol MySecondProtocol
- (id) setVariable: (id)value;
@end
@interface MySubClass : MyRootClass <MyProtocol>
{ id variable_ivar; }
- (void) setVariable: (id)value;
- (id) variable;
@end
@implementation MySubClass
- (void) setVariable: (id)value { variable_ivar = value; }
- (id) variable { return variable_ivar; }
@end
int main ()
{
/* Functions are tested in alphabetical order. */
std::cout << "Testing objc_allocateClassPair ()...\n";
{
Class new_root_class = objc_allocateClassPair (Nil, "MyNewRootClass", 0);
Class new_class = objc_allocateClassPair (objc_getClass ("MyRootClass"), "MyNewSubClass", 0);
/* A new root class would obviously need at least an 'isa'
instance variable. We don't add it so we never actually
instantiate an instance of the class, which wouldn't work. */
objc_registerClassPair (new_root_class);
objc_registerClassPair (new_class);
if (std::strcmp (class_getName (new_class), "MyNewSubClass") != 0)
abort ();
if (class_getSuperclass (new_class) != objc_getClass ("MyRootClass"))
abort ();
if (std::strcmp (class_getName (new_root_class), "MyNewRootClass") != 0)
abort ();
if (class_getSuperclass (new_root_class) != Nil)
abort ();
{
MySubClass *o = [[objc_getClass ("MyNewSubClass") alloc] init];
if (object_getClass (o) != objc_getClass ("MyNewSubClass"))
abort ();
}
}
std::cout << "Testing objc_copyProtocolList ()...\n";
{
/* Make sure both our two protocols are known to the runtime. */
id my_protocol = @protocol (MyProtocol);
id my_second_protocol = @protocol (MySecondProtocol);
unsigned int count;
Protocol ** list = objc_copyProtocolList (&count);
if (count != 2)
abort ();
if (! ((std::strcmp (protocol_getName (list[0]), "MyProtocol") == 0
&& std::strcmp (protocol_getName (list[1]), "MySecondProtocol") == 0)
|| (std::strcmp (protocol_getName (list[0]), "MySecondProtocol") == 0
&& std::strcmp (protocol_getName (list[1]), "MyProtocol") == 0)))
abort ();
if (list[2] != NULL)
abort ();
}
std::cout << "Testing objc_disposeClassPair ()...\n";
{
Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), @selector (setVariable:));
Class new_class = objc_allocateClassPair (objc_getClass ("MyRootClass"), "MyNewSubClass", 0);
/* Add a bit of everything to the class to exercise undoing all these changes. */
/* Instance variable. */
class_addIvar (new_class, "my_variable", sizeof (float), __alignof__ (float), @encode (float));
/* Instance method. */
class_addMethod (new_class, @selector (setVariable:), method_getImplementation (method),
method_getTypeEncoding (method));
/* Class method. */
class_addMethod (object_getClass (new_class), @selector (setVariable:), method_getImplementation (method),
method_getTypeEncoding (method));
/* Protocol. */
class_addProtocol (new_class, @protocol (MyProtocol));
objc_disposeClassPair (new_class);
}
/* This function currently does not exist with the GNU runtime. */
/* std::cout << "Testing objc_duplicateClass ()...\n"; */
/* TODO - Test it when implemented in the GNU Runtime */
/* std::cout << "Testing objc_getAssociatedObject ()...\n"; */
std::cout << "Testing objc_getClass ()...\n";
{
if (std::strcmp (class_getName (objc_getClass ("MySubClass")),
"MySubClass") != 0)
abort ();
}
std::cout << "Testing objc_getClassList ()...\n";
{
Class *list;
int i, count, other_count;
count = objc_getClassList (NULL, 0);
/* count most likely will be 5, (MyRootClass, MySubClass,
Protocol, Object, NXConstantString). */
if (count < 3)
abort ();
list = (Class *)(malloc (sizeof (Class) * count));
other_count = objc_getClassList (list, count);
if (other_count != count)
abort ();
/* Spot-check: search for class 'MyRootClass' in the list. */
for (i = 0; i < count; i++)
{
if (std::strcmp (class_getName (list[i]), "MyRootClass") == 0)
break;
}
if (i == count)
abort ();
/* Spot-check: search for class 'MySubClass' in the list. */
for (i = 0; i < count; i++)
{
if (std::strcmp (class_getName (list[i]), "MySubClass") == 0)
break;
}
if (i == count)
abort ();
/* Spot-check: search for class 'Protocol' in the list. */
for (i = 0; i < count; i++)
{
if (std::strcmp (class_getName (list[i]), "Protocol") == 0)
break;
}
if (i == count)
abort ();
}
/* This function does not exist with the GNU runtime. */
/* std::cout << "Testing objc_getFutureClass ()...\n"; */
std::cout << "Testing objc_getMetaClass ()...\n";
{
if (! class_isMetaClass (objc_getMetaClass ("MyRootClass")))
abort ();
}
std::cout << "Testing objc_getProtocol ()...\n";
{
if (! protocol_isEqual (objc_getProtocol ("MyProtocol"), @protocol (MyProtocol)))
abort ();
}
std::cout << "Testing objc_getRequiredClass ()...\n";
{
if (std::strcmp (class_getName (objc_getRequiredClass ("MyRootClass")),
"MyRootClass") != 0)
abort ();
}
std::cout << "Testing objc_lookupClass ()...\n";
{
if (std::strcmp (class_getName (objc_lookupClass ("MyRootClass")),
"MyRootClass") != 0)
abort ();
}
/* This function does not exist with the GNU runtime. */
/* std::cout << "Testing objc_setFutureClass ()...\n"; */
std::cout << "Testing objc_registerClassPair ()...\n";
{
Class new_class = objc_allocateClassPair (objc_getClass ("MySubClass"), "MySubSubClass", 0);
class_addProtocol (new_class, @protocol (MySecondProtocol));
objc_registerClassPair (new_class);
if (std::strcmp (class_getName (new_class), "MySubSubClass") != 0)
abort ();
if (class_getSuperclass (new_class) != objc_getClass ("MySubClass"))
abort ();
if (! class_conformsToProtocol (new_class, @protocol (MySecondProtocol)))
abort ();
}
/* TODO - Test it when implemented in the GNU Runtime */
/* std::cout << "Testing objc_removeAssociatedObjects ()...\n"; */
/* TODO - Test it when implemented in the GNU Runtime */
/* std::cout << "Testing objc_setAssociatedObject ()...\n"; */
return (0);
}

View File

@ -0,0 +1,161 @@
/* Test the Modern GNU Objective-C Runtime API.
This is test 'object', covering all functions starting with 'object'. */
/* { dg-do run } */
/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */
/* To get the modern GNU Objective-C Runtime API, you include
objc/runtime.h. */
#include <objc/runtime.h>
#include <stdlib.h>
#include <iostream>
#include <cstring>
@interface MyRootClass
{ Class isa; }
+ alloc;
- init;
@end
@implementation MyRootClass
+ alloc { return class_createInstance (self, 0); }
- init { return self; }
@end
@protocol MyProtocol
- (id) variable;
@end
@protocol MySecondProtocol
- (id) setVariable: (id)value;
@end
@interface MySubClass : MyRootClass <MyProtocol>
{ id variable_ivar; }
- (void) setVariable: (id)value;
- (id) variable;
@end
@implementation MySubClass
- (void) setVariable: (id)value { variable_ivar = value; }
- (id) variable { return variable_ivar; }
@end
@interface MySubSubClass : MySubClass
- (id) test;
@end
@implementation MySubSubClass
- (id) test { return self; }
@end
int main ()
{
/* Functions are tested in alphabetical order. */
std::cout << "Testing object_copy () ...\n";
{
MySubClass *object_a = [[MySubClass alloc] init];
MySubClass *object_b = object_copy (object_a, 0);
[object_b setVariable: object_a];
if ([object_b variable] != object_a)
abort ();
}
std::cout << "Testing object_dispose () ...\n";
{
MySubClass *object = [[MySubClass alloc] init];
object_dispose (object);
}
std::cout << "Testing object_getClass () ...\n";
{
MyRootClass *o = [[MySubClass alloc] init];
if (object_getClass (o) != objc_getClass ("MySubClass"))
abort ();
}
std::cout << "Testing object_getClassName () ...\n";
{
MyRootClass *o = [[MyRootClass alloc] init];
if (std::strcmp (object_getClassName (o), "MyRootClass") != 0)
abort ();
}
std::cout << "Testing object_getIndexedIvars () ...\n";
{
if (object_getIndexedIvars ([[MyRootClass alloc] init]) == NULL)
abort ();
}
std::cout << "Testing object_getInstanceVariable () ...\n";
{
MySubClass *o = [[MySubClass alloc] init];
id value;
[o setVariable: o];
if (object_getInstanceVariable (o, "variable_ivar", (void **)&value) == NULL)
abort ();
if (value != o)
abort ();
}
std::cout << "Testing object_getIvar () ...\n";
{
MySubClass *o = [[MySubClass alloc] init];
Ivar ivar = class_getInstanceVariable (objc_getClass ("MySubClass"), "variable_ivar");
[o setVariable: o];
if (object_getIvar (o, ivar) != o)
abort ();
}
std::cout << "Testing object_setClass () ...\n";
{
MySubClass *o = [[MySubClass alloc] init];
object_setClass (o, objc_getClass ("MySubSubClass"));
if ([(MySubSubClass *)o test] != o)
abort ();
}
std::cout << "Testing object_setInstanceVariable () ...\n";
{
MySubClass *o = [[MySubClass alloc] init];
[o setVariable: nil];
if (object_setInstanceVariable (o, "variable_ivar", (void *)o) == NULL)
abort ();
if ([o variable] != o)
abort ();
}
std::cout << "Testing object_setIvar () ...\n";
{
MySubClass *o = [[MySubClass alloc] init];
MySubClass *value = [[MySubClass alloc] init];
Ivar ivar = class_getInstanceVariable (objc_getClass ("MySubClass"), "variable_ivar");
[o setVariable: o];
object_setIvar (o, ivar, value);
if ([o variable] != value)
abort ();
}
return (0);
}

View File

@ -0,0 +1,65 @@
/* Test the Modern GNU Objective-C Runtime API.
This is test 'property', covering all functions starting with 'property'. */
/* { dg-do run } */
/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */
/* To get the modern GNU Objective-C Runtime API, you include
objc/runtime.h. */
#include <objc/runtime.h>
#include <stdlib.h>
#include <iostream>
#include <cstring>
@interface MyRootClass
{ Class isa; }
+ alloc;
- init;
@end
@implementation MyRootClass
+ alloc { return class_createInstance (self, 0); }
- init { return self; }
@end
@protocol MyProtocol
- (id) variable;
@end
@protocol MySecondProtocol
- (id) setVariable: (id)value;
@end
@interface MySubClass : MyRootClass <MyProtocol>
{ id variable_ivar; }
- (void) setVariable: (id)value;
- (id) variable;
@end
@implementation MySubClass
- (void) setVariable: (id)value { variable_ivar = value; }
- (id) variable { return variable_ivar; }
@end
int main ()
{
/* Functions are tested in alphabetical order. */
/* TODO: Test new ABI (when available). */
std::cout << "Testing property_getAttributes () ...\n";
{
if (property_getAttributes (NULL) != NULL)
abort ();
}
/* TODO: Test new ABI (when available). */
std::cout << "Testing property_getName () ...\n";
{
if (property_getName (NULL) != NULL)
abort ();
}
return (0);
}

View File

@ -0,0 +1,160 @@
/* Test the Modern GNU Objective-C Runtime API.
This is test 'protocol', covering all functions starting with 'protocol'. */
/* { dg-do run } */
/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */
/* To get the modern GNU Objective-C Runtime API, you include
objc/runtime.h. */
#include <objc/runtime.h>
#include <stdlib.h>
#include <iostream>
#include <cstring>
@interface MyRootClass
{ Class isa; }
+ alloc;
- init;
@end
@implementation MyRootClass
+ alloc { return class_createInstance (self, 0); }
- init { return self; }
@end
@protocol MyProtocol
- (id) variable;
@end
@protocol MySecondProtocol
- (id) setVariable: (id)value;
@end
@protocol MyThirdProtocol <MySecondProtocol>
- (id) setAnotherVariable: (id)value;
@end
@interface MySubClass : MyRootClass <MyProtocol>
{ id variable_ivar; }
- (void) setVariable: (id)value;
- (id) variable;
@end
@implementation MySubClass
- (void) setVariable: (id)value { variable_ivar = value; }
- (id) variable { return variable_ivar; }
@end
int main ()
{
/* Functions are tested in alphabetical order. */
std::cout << "Testing protocol_conformsToProtocol ()...\n";
{
if (!protocol_conformsToProtocol (@protocol (MyProtocol),
@protocol (MyProtocol)))
abort ();
if (!protocol_conformsToProtocol (@protocol (MyThirdProtocol),
@protocol (MySecondProtocol)))
abort ();
if (protocol_conformsToProtocol (@protocol (MyProtocol),
@protocol (MySecondProtocol)))
abort ();
}
std::cout << "Testing protocol_copyMethodDescriptionList ()...\n";
{
unsigned int count;
struct objc_method_description *list;
list = protocol_copyMethodDescriptionList (@protocol (MyThirdProtocol),
YES, YES, &count);
if (count != 1)
abort ();
if (std::strcmp (sel_getName (list[0].name), "setAnotherVariable:") != 0)
abort ();
if (list[1].name != NULL && list[1].types != NULL)
abort ();
}
/* TODO: Test new ABI (when available). */
std::cout << "Testing protocol_copyPropertyList ()...\n";
{
unsigned int count;
Property *list;
list = protocol_copyPropertyList (@protocol (MyProtocol), &count);
if (count != 0 || list != NULL)
abort ();
}
std::cout << "Testing protocol_copyProtocolList ()...\n";
{
unsigned int count;
Protocol **list;
list = protocol_copyProtocolList (@protocol (MyThirdProtocol), &count);
if (count != 1)
abort ();
if (std::strcmp (protocol_getName (list[0]), "MySecondProtocol") != 0)
abort ();
if (list[1] != NULL)
abort ();
}
std::cout << "Testing protocol_getMethodDescription ()...\n";
{
struct objc_method_description description;
description = protocol_getMethodDescription (@protocol (MySecondProtocol),
@selector (setVariable:),
YES, YES);
if (description.name == NULL && description.types == NULL)
abort ();
if (std::strcmp (sel_getName (description.name), "setVariable:") != 0)
abort ();
}
std::cout << "Testing protocol_getName ()...\n";
{
if (std::strcmp (protocol_getName (@protocol (MyProtocol)), "MyProtocol") != 0)
abort ();
}
/* TODO: Test new ABI (when available). */
std::cout << "Testing protocol_getProperty ()...\n";
{
Property property;
property = protocol_getProperty (objc_getProtocol ("MyProtocol"), "someProperty",
YES, YES);
if (property != NULL)
abort ();
}
std::cout << "Testing protocol_isEqual ()...\n";
{
if (!protocol_isEqual (@protocol (MyProtocol),
@protocol (MyProtocol)))
abort ();
if (!protocol_isEqual (@protocol (MyProtocol),
objc_getProtocol ("MyProtocol")))
abort ();
}
return (0);
}

View File

@ -0,0 +1,103 @@
/* Test the Modern GNU Objective-C Runtime API.
This is test 'sel', covering all functions starting with 'sel'. */
/* { dg-do run } */
/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */
/* To get the modern GNU Objective-C Runtime API, you include
objc/runtime.h. */
#include <objc/runtime.h>
#include <stdlib.h>
#include <iostream>
#include <cstring>
@interface MyRootClass
{ Class isa; }
+ alloc;
- init;
@end
@implementation MyRootClass
+ alloc { return class_createInstance (self, 0); }
- init { return self; }
@end
@protocol MyProtocol
- (id) variable;
@end
@protocol MySecondProtocol
- (id) setVariable: (id)value;
@end
@interface MySubClass : MyRootClass <MyProtocol>
{ id variable_ivar; }
- (void) setVariable: (id)value;
- (id) variable;
@end
@implementation MySubClass
- (void) setVariable: (id)value { variable_ivar = value; }
- (id) variable { return variable_ivar; }
@end
int main ()
{
/* Functions are tested in alphabetical order. */
std::cout << "Testing sel_getName () ...\n";
{
if (std::strcmp (sel_getName (@selector (variable)), "variable") != 0)
abort ();
if (std::strcmp (sel_getName (NULL), "<null selector>") != 0)
abort ();
}
std::cout << "Testing sel_getType () ...\n";
{
/* Get a selector from a real class, so it has interesting
types. */
Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
@selector (variable));
if (std::strcmp (sel_getType (method_getName (method)), method_getTypeEncoding (method)) != 0)
abort ();
}
std::cout << "Testing sel_getUid () ...\n";
{
if (std::strcmp (sel_getName (sel_getUid ("myMethod")), "myMethod") != 0)
abort ();
}
std::cout << "Testing sel_isEqual () ...\n";
{
if (! sel_isEqual (@selector (setVariable:), @selector (setVariable:)))
abort ();
}
std::cout << "Testing sel_registerName () ...\n";
{
if (std::strcmp (sel_getName (sel_registerName ("myMethod")), "myMethod") != 0)
abort ();
}
std::cout << "Testing set_registerTypedName () ...\n";
{
const char *types = method_getTypeEncoding (class_getInstanceMethod
(objc_getClass ("MySubClass"),
@selector (variable)));
SEL selector = sel_registerTypedName ("aMethod", types);
if (std::strcmp (sel_getName (selector), "aMethod") != 0)
abort ();
if (std::strcmp (sel_getType (selector), types) != 0)
abort ();
}
return (0);
}

View File

@ -1,3 +1,8 @@
2010-10-17 Nicola Pero <nicola.pero@meta-innovation.com>
* objc/message.h: Moved initial includes outside of extern "C".
* objc/runtime.h: Add extern "C" for Objective-C++.
2010-10-17 Nicola Pero <nicola.pero@meta-innovation.com>
* init.c (objc_send_load): Do not wait for NXConstantString to be
@ -6,7 +11,7 @@
as is the case for almost all users.
* linking.m (__objc_linking): Do not try to forcefully link in
NXConstantString.
2010-10-16 Nicola Pero <nicola.pero@meta-innovation.com>
* objc/runtime.h: Updated comments.

View File

@ -26,13 +26,13 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#ifndef __objc_message_INCLUDE_GNU
#define __objc_message_INCLUDE_GNU
#include "objc.h"
#include "objc-decls.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "objc.h"
#include "objc-decls.h"
/* This file includes declarations of the messaging functions and
types.
*/

View File

@ -50,6 +50,10 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#include "objc.h"
#include "objc-decls.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* An 'Ivar' represents an instance variable. It holds information
about the name, type and offset of the instance variable. */
typedef struct objc_ivar *Ivar;
@ -1042,4 +1046,8 @@ void objc_layout_structure_get_info (struct objc_struct_layout *layout,
unsigned int *align,
const char **type);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif