Index: src/OFIntrospection.m ================================================================== --- src/OFIntrospection.m +++ src/OFIntrospection.m @@ -31,28 +31,10 @@ - (instancetype)init { OF_INVALID_INIT_METHOD } -#if defined(OF_OBJFW_RUNTIME) -- (instancetype)of_initWithMethod: (struct objc_method *)method -{ - self = [super init]; - - @try { - _selector = (SEL)&method->selector; - _name = [[OFString alloc] - initWithUTF8String: sel_getName(_selector)]; - _typeEncoding = method->selector.typeEncoding; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} -#elif defined(OF_APPLE_RUNTIME) - (instancetype)of_initWithMethod: (Method)method { self = [super init]; @try { @@ -65,13 +47,10 @@ @throw e; } return self; } -#else -# error Invalid ObjC runtime! -#endif - (void)dealloc { [_name release]; @@ -440,63 +419,25 @@ - (instancetype)initWithClass: (Class)class { self = [super init]; @try { + Method *methodList; + Ivar *iVarList; #if defined(OF_OBJFW_RUNTIME) - 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; void *pool; _classMethods = [[OFMutableArray alloc] init]; _instanceMethods = [[OFMutableArray alloc] init]; _properties = [[OFMutableArray alloc] init]; _instanceVariables = [[OFMutableArray alloc] init]; -#if defined(OF_OBJFW_RUNTIME) - for (methodList = object_getClass(class)->methodList; - methodList != NULL; methodList = methodList->next) { - pool = objc_autoreleasePoolPush(); - - for (unsigned int i = 0; i < methodList->count; i++) - [_classMethods addObject: [[[OFMethod alloc] - of_initWithMethod: - &methodList->methods[i]] autorelease]]; - - objc_autoreleasePoolPop(pool); - } - - for (methodList = class->methodList; methodList != NULL; - methodList = methodList->next) { - pool = objc_autoreleasePoolPush(); - - for (unsigned int i = 0; i < methodList->count; i++) - [_instanceMethods addObject: [[[OFMethod alloc] - of_initWithMethod: - &methodList->methods[i]] autorelease]]; - - objc_autoreleasePoolPop(pool); - } - - for (propertyList = class->properties; propertyList != NULL; - propertyList = propertyList->next) { - pool = objc_autoreleasePoolPush(); - - for (unsigned int i = 0; i < propertyList->count; i++) - [_properties addObject: [[[OFProperty alloc] - of_initWithProperty: - &propertyList->properties[i]] autorelease]]; - - objc_autoreleasePoolPop(pool); - } -#elif defined(OF_APPLE_RUNTIME) methodList = class_copyMethodList(object_getClass(class), &count); @try { pool = objc_autoreleasePoolPush(); @@ -522,10 +463,37 @@ objc_autoreleasePoolPop(pool); } @finally { free(methodList); } + iVarList = class_copyIvarList(class, &count); + @try { + pool = objc_autoreleasePoolPush(); + + for (unsigned int i = 0; i < count; i++) + [_instanceVariables addObject: + [[[OFInstanceVariable alloc] + of_initWithIVar: iVarList[i]] autorelease]]; + + objc_autoreleasePoolPop(pool); + } @finally { + free(iVarList); + } + +#if defined(OF_OBJFW_RUNTIME) + for (propertyList = class->properties; propertyList != NULL; + propertyList = propertyList->next) { + pool = objc_autoreleasePoolPush(); + + for (unsigned int i = 0; i < propertyList->count; i++) + [_properties addObject: [[[OFProperty alloc] + of_initWithProperty: + &propertyList->properties[i]] autorelease]]; + + objc_autoreleasePoolPop(pool); + } +#elif defined(OF_APPLE_RUNTIME) propertyList = class_copyPropertyList(class, &count); @try { pool = objc_autoreleasePoolPush(); for (unsigned int i = 0; i < count; i++) @@ -539,24 +507,10 @@ } #else # error Invalid ObjC runtime! #endif - iVarList = class_copyIvarList(class, &count); - @try { - pool = objc_autoreleasePoolPush(); - - for (unsigned int i = 0; i < count; i++) - [_instanceVariables addObject: - [[[OFInstanceVariable alloc] - of_initWithIVar: iVarList[i]] autorelease]]; - - objc_autoreleasePoolPop(pool); - } @finally { - free(iVarList); - } - [_classMethods makeImmutable]; [_instanceMethods makeImmutable]; [_properties makeImmutable]; [_instanceVariables makeImmutable]; } @catch (id e) { Index: src/OFObject.m ================================================================== --- src/OFObject.m +++ src/OFObject.m @@ -362,55 +362,16 @@ } + (void)inheritMethodsFromClass: (Class)class { Class superclass = [self superclass]; + Method *methodList; + unsigned int count; if ([self isSubclassOfClass: class]) return; -#if defined(OF_OBJFW_RUNTIME) - for (struct objc_method_list *methodList = - object_getClass(class)->methodList; - methodList != NULL; methodList = methodList->next) { - for (unsigned int i = 0; i < methodList->count; i++) { - SEL selector = (SEL)&methodList->methods[i].selector; - - /* - * Don't replace methods implemented in the receiving - * class. - */ - if ([self methodForSelector: selector] != - [superclass methodForSelector: selector]) - continue; - - [self replaceClassMethod: selector - withMethodFromClass: class]; - } - } - - for (struct objc_method_list *methodList = class->methodList; - methodList != NULL; methodList = methodList->next) { - for (unsigned int i = 0; i < methodList->count; i++) { - SEL selector = (SEL)&methodList->methods[i].selector; - - /* - * Don't replace methods implemented in the receiving - * class. - */ - if ([self instanceMethodForSelector: selector] != - [superclass instanceMethodForSelector: selector]) - continue; - - [self replaceInstanceMethod: selector - withMethodFromClass: class]; - } - } -#elif defined(OF_APPLE_RUNTIME) - Method *methodList; - unsigned int count; - methodList = class_copyMethodList(object_getClass(class), &count); @try { for (unsigned int i = 0; i < count; i++) { SEL selector = method_getName(methodList[i]); @@ -446,11 +407,10 @@ withMethodFromClass: class]; } } @finally { free(methodList); } -#endif [self inheritMethodsFromClass: superclass]; } + (bool)resolveClassMethod: (SEL)selector Index: src/runtime/Makefile ================================================================== --- src/runtime/Makefile +++ src/runtime/Makefile @@ -18,10 +18,11 @@ exception.m \ hashtable.m \ init.m \ ivar.m \ lookup.m \ + method.m \ misc.m \ property.m \ protocol.m \ selector.m \ sparsearray.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 const struct objc_method *Method; typedef const struct objc_ivar *Ivar; #if !defined(__wii__) && !defined(__amigaos__) typedef bool BOOL; #endif typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...); @@ -96,47 +97,19 @@ OBJC_CLASS_INFO_LOADED = 0x200, OBJC_CLASS_INFO_DTABLE = 0x400, OBJC_CLASS_INFO_INITIALIZED = 0x800 }; -struct objc_object { - Class _Nonnull isa; -}; - -struct objc_selector { - uintptr_t UID; - const char *_Nullable typeEncoding; -}; - struct objc_super { id __unsafe_unretained _Nullable self; #ifdef __cplusplus Class _Nonnull class_; #else Class _Nonnull class; #endif }; -struct objc_method { - struct objc_selector selector; - IMP _Nonnull implementation; -}; - -struct objc_method_list { - struct objc_method_list *_Nullable next; - unsigned int count; - struct objc_method methods[1]; -}; - -struct objc_category { - const char *_Nonnull categoryName; - const char *_Nonnull className; - struct objc_method_list *_Nullable instanceMethods; - struct objc_method_list *_Nullable classMethods; - struct objc_protocol_list *_Nullable protocols; -}; - enum objc_property_attributes { OBJC_PROPERTY_READONLY = 0x01, OBJC_PROPERTY_GETTER = 0x02, OBJC_PROPERTY_ASSIGN = 0x04, OBJC_PROPERTY_READWRITE = 0x08, @@ -248,10 +221,14 @@ 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 Method _Nullable *_Nullable class_copyMethodList(Class _Nullable class_, + unsigned int *_Nullable outCount); +extern SEL _Nonnull method_getName(Method _Nonnull method); +extern const char *_Nullable method_getTypeEncoding(Method _Nonnull method); 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); Index: src/runtime/amiga-glue.m ================================================================== --- src/runtime/amiga-glue.m +++ src/runtime/amiga-glue.m @@ -664,5 +664,30 @@ { M68K_ARG(Ivar, ivar, a0) return ivar_getOffset(ivar); } + +Method * +glue_class_copyMethodList PPC_PARAMS(Class class, unsigned int *outCount) +{ + M68K_ARG(Class, class, a0) + M68K_ARG(unsigned int *, outCount, a1) + + return class_copyMethodList(class, outCount); +} + +SEL +glue_method_getName PPC_PARAMS(Method method) +{ + M68K_ARG(Method, method, a0) + + return method_getName(method); +} + +const char * +glue_method_getTypeEncoding PPC_PARAMS(Method method) +{ + M68K_ARG(Method, method, a0) + + return method_getTypeEncoding(method); +} Index: src/runtime/amiga-library.m ================================================================== --- src/runtime/amiga-library.m +++ src/runtime/amiga-library.m @@ -130,10 +130,13 @@ 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); +extern Method *glue_class_copyMethodList(void); +extern SEL glue_method_getName(void); +extern const char *glue_method_getTypeEncoding(void); #ifdef OF_MORPHOS const ULONG __abox__ = 1; #endif struct ExecBase *SysBase; @@ -641,10 +644,13 @@ (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)glue_class_copyMethodList, + (CONST_APTR)glue_method_getName, + (CONST_APTR)glue_method_getTypeEncoding, (CONST_APTR)-1, #ifdef OF_MORPHOS (CONST_APTR)FUNCARRAY_END #endif }; Index: src/runtime/amigaos3.sfd ================================================================== --- src/runtime/amigaos3.sfd +++ src/runtime/amigaos3.sfd @@ -73,6 +73,9 @@ 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) +Method _Nullable *_Nullable glue_class_copyMethodList(Class _Nullable class_, unsigned int *_Nullable outCount)(a0,a1) +SEL _Nonnull glue_method_getName(Method _Nonnull method)(a0) +const char *_Nullable glue_method_getTypeEncoding(Method _Nonnull method)(a0) ==end Index: src/runtime/ivar.m ================================================================== --- src/runtime/ivar.m +++ src/runtime/ivar.m @@ -24,31 +24,31 @@ class_copyIvarList(Class class, unsigned int *outCount) { unsigned int count; Ivar *ivars; - if (class == Nil) - return NULL; + if (class == Nil) { + if (outCount != NULL) + *outCount = 0; - objc_global_mutex_lock(); - - if (class->ivars == NULL) { - objc_global_mutex_unlock(); return NULL; } - count = class->ivars->count; + objc_global_mutex_lock(); + + count = (class->ivars != NULL ? class->ivars->count : 0); if (count == 0) { + if (outCount != NULL) + *outCount = 0; + objc_global_mutex_unlock(); return NULL; } - if ((ivars = malloc((count + 1) * sizeof(Ivar))) == NULL) { - objc_global_mutex_unlock(); - return NULL; - } + if ((ivars = malloc((count + 1) * sizeof(Ivar))) == NULL) + OBJC_ERROR("Not enough memory to copy ivars"); for (unsigned int i = 0; i < count; i++) ivars[i] = &class->ivars->ivars[i]; ivars[count] = NULL; Index: src/runtime/linklib/linklib.m ================================================================== --- src/runtime/linklib/linklib.m +++ src/runtime/linklib/linklib.m @@ -613,5 +613,23 @@ ptrdiff_t ivar_getOffset(Ivar ivar) { return glue_ivar_getOffset(ivar); } + +Method * +class_copyMethodList(Class class, unsigned int *outCount) +{ + return glue_class_copyMethodList(class, outCount); +} + +SEL +method_getName(Method method) +{ + return glue_method_getName(method); +} + +const char * +method_getTypeEncoding(Method method) +{ + return glue_method_getTypeEncoding(method); +} ADDED src/runtime/method.m Index: src/runtime/method.m ================================================================== --- src/runtime/method.m +++ src/runtime/method.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" + +Method * +class_copyMethodList(Class class, unsigned int *outCount) +{ + unsigned int i, count; + struct objc_method_list *iter; + Method *methods; + + if (class == Nil) { + if (outCount != NULL) + *outCount = 0; + + return NULL; + } + + objc_global_mutex_lock(); + + count = 0; + for (iter = class->methodList; iter != NULL; iter = iter->next) + count += iter->count; + + if (count == 0) { + if (outCount != NULL) + *outCount = 0; + + objc_global_mutex_unlock(); + return NULL; + } + + if ((methods = malloc((count + 1) * sizeof(Method))) == NULL) + OBJC_ERROR("Not enough memory to copy methods"); + + i = 0; + for (iter = class->methodList; iter != NULL; iter = iter->next) + for (unsigned int j = 0; j < iter->count; j++) + methods[i++] = &iter->methods[j]; + OF_ENSURE(i == count); + methods[count] = NULL; + + if (outCount != NULL) + *outCount = count; + + objc_global_mutex_unlock(); + + return methods; +} + +SEL +method_getName(Method method) +{ + return (SEL)&method->selector; +} + +const char * +method_getTypeEncoding(Method method) +{ + return method->selector.typeEncoding; +} Index: src/runtime/morphos-clib.h ================================================================== --- src/runtime/morphos-clib.h +++ src/runtime/morphos-clib.h @@ -67,5 +67,8 @@ 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); +Method *glue_class_copyMethodList(Class class_, unsigned int *outCount); +SEL glue_method_getName(Method method); +const char *glue_method_getTypeEncoding(Method method); Index: src/runtime/morphos.fd ================================================================== --- src/runtime/morphos.fd +++ src/runtime/morphos.fd @@ -69,6 +69,9 @@ 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) +glue_class_copyMethodList(class_,outCount)(sysv,r12base) +glue_method_getName(method)(sysv,r12base) +glue_method_getTypeEncoding(method)(sysv,r12base) ##end Index: src/runtime/private.h ================================================================== --- src/runtime/private.h +++ src/runtime/private.h @@ -26,10 +26,38 @@ # endif # ifndef _Nullable # define _Nullable # endif #endif + +struct objc_object { + Class _Nonnull isa; +}; + +struct objc_selector { + uintptr_t UID; + const char *_Nullable typeEncoding; +}; + +struct objc_method { + struct objc_selector selector; + IMP _Nonnull implementation; +}; + +struct objc_method_list { + struct objc_method_list *_Nullable next; + unsigned int count; + struct objc_method methods[1]; +}; + +struct objc_category { + const char *_Nonnull categoryName; + const char *_Nonnull className; + 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;