Index: src/OFIntrospection.m ================================================================== --- src/OFIntrospection.m +++ src/OFIntrospection.m @@ -386,30 +386,10 @@ - (instancetype)init { OF_INVALID_INIT_METHOD } -#if defined(OF_OBJFW_RUNTIME) -- (instancetype)of_initWithIVar: (struct objc_ivar *)iVar -{ - self = [super init]; - - @try { - if (iVar->name != NULL) - _name = [[OFString alloc] - initWithUTF8String: iVar->name]; - - _typeEncoding = iVar->typeEncoding; - _offset = iVar->offset; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} -#elif defined(OF_APPLE_RUNTIME) - (instancetype)of_initWithIVar: (Ivar)iVar { self = [super init]; @try { @@ -425,13 +405,10 @@ @throw e; } return self; } -#else -# error Invalid ObjC runtime! -#endif - (void)dealloc { [_name release]; @@ -469,13 +446,13 @@ struct objc_method_list *methodList; struct objc_property_list *propertyList; #elif defined(OF_APPLE_RUNTIME) Method *methodList; objc_property_t *propertyList; +#endif Ivar *iVarList; unsigned count; -#endif void *pool; _classMethods = [[OFMutableArray alloc] init]; _instanceMethods = [[OFMutableArray alloc] init]; _properties = [[OFMutableArray alloc] init]; @@ -513,22 +490,10 @@ for (unsigned int i = 0; i < propertyList->count; i++) [_properties addObject: [[[OFProperty alloc] of_initWithProperty: &propertyList->properties[i]] autorelease]]; - objc_autoreleasePoolPop(pool); - } - - if (class->iVars != NULL) { - pool = objc_autoreleasePoolPush(); - - for (unsigned int i = 0; i < class->iVars->count; i++) - [_instanceVariables addObject: - [[[OFInstanceVariable alloc] - of_initWithIVar: - &class->iVars->iVars[i]] autorelease]]; - objc_autoreleasePoolPop(pool); } #elif defined(OF_APPLE_RUNTIME) methodList = class_copyMethodList(object_getClass(class), &count); @@ -570,10 +535,13 @@ objc_autoreleasePoolPop(pool); } @finally { free(propertyList); } +#else +# error Invalid ObjC runtime! +#endif iVarList = class_copyIvarList(class, &count); @try { pool = objc_autoreleasePoolPush(); @@ -584,13 +552,10 @@ objc_autoreleasePoolPop(pool); } @finally { free(iVarList); } -#else -# error Invalid ObjC runtime! -#endif [_classMethods makeImmutable]; [_instanceMethods makeImmutable]; [_properties makeImmutable]; [_instanceVariables makeImmutable]; Index: src/runtime/Makefile ================================================================== --- src/runtime/Makefile +++ src/runtime/Makefile @@ -16,10 +16,11 @@ class.m \ dtable.m \ exception.m \ hashtable.m \ init.m \ + ivar.m \ lookup.m \ misc.m \ property.m \ protocol.m \ selector.m \ Index: src/runtime/ObjFWRT.h ================================================================== --- src/runtime/ObjFWRT.h +++ src/runtime/ObjFWRT.h @@ -59,10 +59,11 @@ #define NO false typedef struct objc_class *Class; typedef struct objc_object *id; typedef const struct objc_selector *SEL; +typedef struct objc_ivar *Ivar; #if !defined(__wii__) && !defined(__amigaos__) typedef bool BOOL; #endif typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...); typedef void (*objc_uncaught_exception_handler_t)(id _Nullable); @@ -73,19 +74,19 @@ Class _Nullable superclass; const char *_Nonnull name; unsigned long version; unsigned long info; long instanceSize; - struct objc_ivar_list *_Nullable iVars; + struct objc_ivar_list *_Nullable ivars; struct objc_method_list *_Nullable methodList; struct objc_dtable *_Nonnull DTable; Class _Nullable *_Nullable subclassList; void *_Nullable siblingClass; struct objc_protocol_list *_Nullable protocols; void *_Nullable GCObjectType; unsigned long ABIVersion; - int32_t *_Nonnull *_Nullable iVarOffsets; + int32_t *_Nonnull *_Nullable ivarOffsets; struct objc_property_list *_Nullable properties; }; enum objc_class_info { OBJC_CLASS_INFO_CLASS = 0x001, @@ -132,21 +133,10 @@ struct objc_method_list *_Nullable instanceMethods; struct objc_method_list *_Nullable classMethods; struct objc_protocol_list *_Nullable protocols; }; -struct objc_ivar { - const char *_Nonnull name; - const char *_Nonnull typeEncoding; - unsigned int offset; -}; - -struct objc_ivar_list { - unsigned int count; - struct objc_ivar iVars[1]; -}; - enum objc_property_attributes { OBJC_PROPERTY_READONLY = 0x01, OBJC_PROPERTY_GETTER = 0x02, OBJC_PROPERTY_ASSIGN = 0x04, OBJC_PROPERTY_READWRITE = 0x08, @@ -258,10 +248,15 @@ extern const char *_Nonnull protocol_getName(Protocol *_Nonnull protocol); extern bool protocol_isEqual(Protocol *_Nonnull protocol1, Protocol *_Nonnull protocol2); extern bool protocol_conformsToProtocol(Protocol *_Nonnull protocol1, Protocol *_Nonnull protocol2); +extern Ivar _Nullable *_Nullable class_copyIvarList(Class _Nullable class_, + unsigned int *_Nullable outCount); +extern const char *_Nonnull ivar_getName(Ivar _Nonnull ivar); +extern const char *_Nonnull ivar_getTypeEncoding(Ivar _Nonnull ivar); +extern ptrdiff_t ivar_getOffset(Ivar _Nonnull ivar); extern void objc_exit(void); extern _Nullable objc_uncaught_exception_handler_t objc_setUncaughtExceptionHandler( objc_uncaught_exception_handler_t _Nullable handler); extern void objc_setForwardHandler(IMP _Nullable forward, Index: src/runtime/amiga-glue.m ================================================================== --- src/runtime/amiga-glue.m +++ src/runtime/amiga-glue.m @@ -631,5 +631,38 @@ void __saveds glue_objc_exit(void) { objc_exit(); } + +Ivar *__saveds +glue_class_copyIvarList PPC_PARAMS(Class class, unsigned int *outCount) +{ + M68K_ARG(Class, class, a0) + M68K_ARG(unsigned int *, outCount, a1) + + return class_copyIvarList(class, outCount); +} + +const char *__saveds +glue_ivar_getName PPC_PARAMS(Ivar ivar) +{ + M68K_ARG(Ivar, ivar, a0) + + return ivar_getName(ivar); +} + +const char *__saveds +glue_ivar_getTypeEncoding PPC_PARAMS(Ivar ivar) +{ + M68K_ARG(Ivar, ivar, a0) + + return ivar_getTypeEncoding(ivar); +} + +ptrdiff_t __saveds +glue_ivar_getOffset PPC_PARAMS(Ivar ivar) +{ + M68K_ARG(Ivar, ivar, a0) + + return ivar_getOffset(ivar); +} Index: src/runtime/amiga-library.m ================================================================== --- src/runtime/amiga-library.m +++ src/runtime/amiga-library.m @@ -126,10 +126,14 @@ glue_objc_setUncaughtExceptionHandler(void); extern void glue_objc_setForwardHandler(void); extern void glue_objc_setEnumerationMutationHandler(void); extern void glue_objc_zero_weak_references(void); extern void glue_objc_exit(void); +extern Ivar *glue_class_copyIvarList(void); +extern const char *glue_ivar_getName(void); +extern const char *glue_ivar_getTypeEncoding(void); +extern ptrdiff_t glue_ivar_getOffset(void); #ifdef OF_MORPHOS const ULONG __abox__ = 1; #endif struct ExecBase *SysBase; @@ -633,10 +637,14 @@ (CONST_APTR)glue_objc_setUncaughtExceptionHandler, (CONST_APTR)glue_objc_setForwardHandler, (CONST_APTR)glue_objc_setEnumerationMutationHandler, (CONST_APTR)glue_objc_zero_weak_references, (CONST_APTR)glue_objc_exit, + (CONST_APTR)glue_class_copyIvarList, + (CONST_APTR)glue_ivar_getName, + (CONST_APTR)glue_ivar_getTypeEncoding, + (CONST_APTR)glue_ivar_getOffset, (CONST_APTR)-1, #ifdef OF_MORPHOS (CONST_APTR)FUNCARRAY_END #endif }; Index: src/runtime/amigaos3.sfd ================================================================== --- src/runtime/amigaos3.sfd +++ src/runtime/amigaos3.sfd @@ -69,6 +69,10 @@ _Nullable objc_uncaught_exception_handler_t glue_objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler_t _Nullable handler)(a0) void glue_objc_setForwardHandler(IMP _Nullable forward, IMP _Nullable stretForward)(a0,a1) void glue_objc_setEnumerationMutationHandler(objc_enumeration_mutation_handler_t _Nullable handler)(a0) void glue_objc_zero_weak_references(id _Nonnull value)(a0) void glue_objc_exit(void)() +Ivar _Nullable *_Nullable glue_class_copyIvarList(Class _Nullable class_, unsigned int *_Nullable outCount)(a0,a1) +const char *_Nonnull glue_ivar_getName(Ivar _Nonnull ivar)(a0) +const char *_Nonnull glue_ivar_getTypeEncoding(Ivar _Nonnull ivar)(a0) +ptrdiff_t glue_ivar_getOffset(Ivar _Nonnull ivar)(a0) ==end Index: src/runtime/class.m ================================================================== --- src/runtime/class.m +++ src/runtime/class.m @@ -255,13 +255,12 @@ class->superclass->subclassList[i] = class; class->superclass->subclassList[i + 1] = Nil; } - static void -updateIVarOffsets(Class class) +updateIvarOffsets(Class class) { if (!(class->info & OBJC_CLASS_INFO_NEW_ABI)) return; if (class->instanceSize > 0) @@ -270,21 +269,21 @@ class->instanceSize = -class->instanceSize; if (class->superclass != Nil) { class->instanceSize += class->superclass->instanceSize; - if (class->iVars != NULL) { - for (unsigned int i = 0; i < class->iVars->count; i++) { - class->iVars->iVars[i].offset += + if (class->ivars != NULL) { + for (unsigned int i = 0; i < class->ivars->count; i++) { + class->ivars->ivars[i].offset += class->superclass->instanceSize; - *class->iVarOffsets[i] = - class->iVars->iVars[i].offset; + *class->ivarOffsets[i] = + class->ivars->ivars[i].offset; } } } else - for (unsigned int i = 0; i < class->iVars->count; i++) - *class->iVarOffsets[i] = class->iVars->iVars[i].offset; + for (unsigned int i = 0; i < class->ivars->count; i++) + *class->ivarOffsets[i] = class->ivars->ivars[i].offset; } static void setupClass(Class class) { @@ -311,11 +310,11 @@ addSubclass(class); addSubclass(class->isa); } else class->isa->superclass = class; - updateIVarOffsets(class); + updateIvarOffsets(class); class->info |= OBJC_CLASS_INFO_SETUP; class->isa->info |= OBJC_CLASS_INFO_SETUP; } ADDED src/runtime/ivar.m Index: src/runtime/ivar.m ================================================================== --- src/runtime/ivar.m +++ src/runtime/ivar.m @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, + * 2018, 2019 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#import "ObjFWRT.h" +#import "private.h" + +Ivar * +class_copyIvarList(Class class, unsigned int *outCount) +{ + unsigned int count; + Ivar *ivars; + + if (class == Nil) + return NULL; + + objc_global_mutex_lock(); + + if (class->ivars == NULL) { + objc_global_mutex_unlock(); + return NULL; + } + + count = class->ivars->count; + + if (count == 0) { + objc_global_mutex_unlock(); + return NULL; + } + + if ((ivars = malloc((count + 1) * sizeof(Ivar))) == NULL) { + objc_global_mutex_unlock(); + return NULL; + } + + for (unsigned int i = 0; i < count; i++) + ivars[i] = &class->ivars->ivars[i]; + ivars[count] = NULL; + + if (outCount != NULL) + *outCount = count; + + objc_global_mutex_unlock(); + + return ivars; +} + +const char * +ivar_getName(Ivar ivar) +{ + return ivar->name; +} + +const char * +ivar_getTypeEncoding(Ivar ivar) +{ + return ivar->typeEncoding; +} + +ptrdiff_t +ivar_getOffset(Ivar ivar) +{ + return ivar->offset; +} Index: src/runtime/linklib/linklib.m ================================================================== --- src/runtime/linklib/linklib.m +++ src/runtime/linklib/linklib.m @@ -589,5 +589,29 @@ void objc_exit(void) { glue_objc_exit(); } + +Ivar * +class_copyIvarList(Class class, unsigned int *outCount) +{ + return glue_class_copyIvarList(class, outCount); +} + +const char * +ivar_getName(Ivar ivar) +{ + return glue_ivar_getName(ivar); +} + +const char * +ivar_getTypeEncoding(Ivar ivar) +{ + return glue_ivar_getTypeEncoding(ivar); +} + +ptrdiff_t +ivar_getOffset(Ivar ivar) +{ + return glue_ivar_getOffset(ivar); +} Index: src/runtime/morphos-clib.h ================================================================== --- src/runtime/morphos-clib.h +++ src/runtime/morphos-clib.h @@ -63,5 +63,9 @@ objc_uncaught_exception_handler_t glue_objc_setUncaughtExceptionHandler(objc_uncaught_exception_handler_t); void glue_objc_setForwardHandler(IMP, IMP); void glue_objc_setEnumerationMutationHandler(objc_enumeration_mutation_handler_t); void glue_objc_zero_weak_references(id); void glue_objc_exit(void); +Ivar *glue_class_copyIvarList(Class class_, unsigned int *outCount); +const char *glue_ivar_getName(Ivar ivar); +const char *glue_ivar_getTypeEncoding(Ivar ivar); +ptrdiff_t glue_ivar_getOffset(Ivar ivar); Index: src/runtime/morphos.fd ================================================================== --- src/runtime/morphos.fd +++ src/runtime/morphos.fd @@ -65,6 +65,10 @@ glue_objc_setUncaughtExceptionHandler(handler)(sysv,r12base) glue_objc_setForwardHandler(forward,stretForward)(sysv,r12base) glue_objc_setEnumerationMutationHandler(handler)(sysv,r12base) glue_objc_zero_weak_references(value)(sysv,r12base) glue_objc_exit()(sysv,r12base) +glue_class_copyIvarList(class_,outCount)(sysv,r12base) +glue_ivar_getName(ivar)(sysv,r12base) +glue_ivar_getTypeEncoding(ivar)(sysv,r12base) +glue_ivar_getOffset(ivar)(sysv,r12base) ##end Index: src/runtime/private.h ================================================================== --- src/runtime/private.h +++ src/runtime/private.h @@ -34,19 +34,19 @@ const char *_Nullable superclass; const char *_Nonnull name; unsigned long version; unsigned long info; long instanceSize; - void *_Nullable iVars; + void *_Nullable ivars; struct objc_abi_method_list *_Nullable methodList; void *_Nullable DTable; void *_Nullable subclassList; void *_Nullable siblingClass; void *_Nullable protocols; void *_Nullable GCObjectType; long ABIVersion; - int32_t *_Nonnull *_Nullable iVarOffsets; + int32_t *_Nonnull *_Nullable ivarOffsets; void *_Nullable properties; }; struct objc_abi_selector { const char *_Nonnull name; @@ -61,10 +61,21 @@ struct objc_abi_method_list { struct objc_abi_method_list *_Nullable next; unsigned int count; struct objc_abi_method methods[1]; }; + +struct objc_ivar { + const char *_Nonnull name; + const char *_Nonnull typeEncoding; + unsigned int offset; +}; + +struct objc_ivar_list { + unsigned int count; + struct objc_ivar ivars[1]; +}; struct objc_abi_category { const char *_Nonnull categoryName; const char *_Nonnull className; struct objc_abi_method_list *_Nullable instanceMethods;