mirror of
https://github.com/darlinghq/darling-libobjc2.git
synced 2024-11-27 06:00:30 +00:00
Lots of tidying, removing legacy stuff.
This commit is contained in:
parent
1f7f5cbfab
commit
779b28abeb
18
GNUmakefile
18
GNUmakefile
@ -8,9 +8,7 @@ libobjc_VERSION = 4
|
||||
|
||||
libobjc_OBJC_FILES = \
|
||||
NSBlocks.m\
|
||||
NXConstStr.m\
|
||||
Object.m\
|
||||
Protocol.m\
|
||||
Protocol2.m\
|
||||
blocks_runtime.m\
|
||||
mutation.m\
|
||||
properties.m\
|
||||
@ -28,7 +26,6 @@ libobjc_C_FILES = \
|
||||
hooks.c\
|
||||
ivar.c\
|
||||
loader.c\
|
||||
misc.c\
|
||||
protocol.c\
|
||||
runtime.c\
|
||||
sarray2.c\
|
||||
@ -38,6 +35,7 @@ libobjc_C_FILES = \
|
||||
|
||||
ifneq ($(enable_legacy), no)
|
||||
libobjc_C_FILES += \
|
||||
legacy_malloc.c\
|
||||
objects.c\
|
||||
thr.c
|
||||
endif
|
||||
@ -86,15 +84,3 @@ endif
|
||||
|
||||
include $(GNUSTEP_MAKEFILES)/aggregate.make
|
||||
include $(GNUSTEP_MAKEFILES)/library.make
|
||||
|
||||
ifeq ($(findstring no, $(debug)),)
|
||||
before-all::
|
||||
@echo
|
||||
@echo
|
||||
@echo WARNING: You are building in debug mode. This will generate a LOT of console \
|
||||
output for every Objective-C program you run. If this is not what you \
|
||||
want, please compile with $(MAKE) debug=no
|
||||
@echo
|
||||
@echo
|
||||
endif
|
||||
|
||||
|
19
NSBlocks.m
19
NSBlocks.m
@ -1,5 +1,8 @@
|
||||
#import "objc/objc-api.h"
|
||||
#import "objc/runtime.h"
|
||||
#import "class.h"
|
||||
#import "lock.h"
|
||||
#import "objc/blocks_runtime.h"
|
||||
#import "dtable.h"
|
||||
#include <assert.h>
|
||||
|
||||
struct objc_class _NSConcreteGlobalBlock;
|
||||
@ -11,28 +14,24 @@ static struct objc_class _NSConcreteStackBlockMeta;
|
||||
static struct objc_class _NSBlock;
|
||||
static struct objc_class _NSBlockMeta;
|
||||
|
||||
void __objc_update_dispatch_table_for_class(Class);
|
||||
void __objc_add_class_to_hash(Class);
|
||||
extern struct sarray *__objc_uninstalled_dtable;
|
||||
extern objc_mutex_t __objc_runtime_mutex;
|
||||
|
||||
static void createNSBlockSubclass(Class superclass, Class newClass,
|
||||
Class metaClass, char *name)
|
||||
{
|
||||
// Initialize the metaclass
|
||||
//metaClass->class_pointer = superclass->class_pointer;
|
||||
//metaClass->super_class = superclass->class_pointer;
|
||||
metaClass->info = _CLS_META;
|
||||
metaClass->info = objc_class_flag_meta;
|
||||
metaClass->dtable = __objc_uninstalled_dtable;
|
||||
|
||||
// Set up the new class
|
||||
newClass->class_pointer = metaClass;
|
||||
newClass->isa = metaClass;
|
||||
newClass->super_class = (Class)superclass->name;
|
||||
newClass->name = name;
|
||||
newClass->info = _CLS_CLASS;
|
||||
newClass->info = objc_class_flag_class;
|
||||
newClass->dtable = __objc_uninstalled_dtable;
|
||||
|
||||
__objc_add_class_to_hash(newClass);
|
||||
LOCK_UNTIL_RETURN(__objc_runtime_mutex);
|
||||
class_table_insert(newClass);
|
||||
|
||||
}
|
||||
|
||||
|
45
NXConstStr.m
45
NXConstStr.m
@ -1,45 +0,0 @@
|
||||
/* Implementation of the NXConstantString class for Objective-C.
|
||||
Copyright (C) 1995, 2009 Free Software Foundation, Inc.
|
||||
Contributed by Pieter J. Schoenmakers <tiggr@es.ele.tue.nl>
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3, or (at your option) any
|
||||
later version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "objc/NXConstStr.h"
|
||||
#include "objc/objc-api.h"
|
||||
|
||||
@implementation NXConstantString
|
||||
+ (void)load
|
||||
{
|
||||
__CLS_INFO((Class)self) &= ~_CLS_PLANE_AWARE;
|
||||
}
|
||||
|
||||
-(const char *) cString
|
||||
{
|
||||
return (c_string);
|
||||
} /* -cString */
|
||||
|
||||
-(unsigned int) length
|
||||
{
|
||||
return (len);
|
||||
} /* -length */
|
||||
|
||||
@end
|
360
Object.m
360
Object.m
@ -1,360 +0,0 @@
|
||||
/* The implementation of class Object for Objective-C.
|
||||
Copyright (C) 1993, 1994, 1995, 1997, 2002, 2009 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 3, or (at your option) any
|
||||
later version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include "objc/Object.h"
|
||||
#include "objc/Protocol.h"
|
||||
#include "objc/objc-api.h"
|
||||
|
||||
#define MAX_CLASS_NAME_LEN 256
|
||||
|
||||
@implementation Object
|
||||
|
||||
+ (void)load
|
||||
{
|
||||
__CLS_INFO((Class)self) &= ~_CLS_PLANE_AWARE;
|
||||
}
|
||||
+ initialize
|
||||
{
|
||||
// Object subclasses are not plane aware either.
|
||||
__CLS_INFO((Class)self) &= ~_CLS_PLANE_AWARE;
|
||||
return self;
|
||||
}
|
||||
|
||||
- init
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
+ new
|
||||
{
|
||||
return [[self alloc] init];
|
||||
}
|
||||
|
||||
+ alloc
|
||||
{
|
||||
return class_create_instance(self);
|
||||
}
|
||||
|
||||
- free
|
||||
{
|
||||
return object_dispose(self);
|
||||
}
|
||||
|
||||
- copy
|
||||
{
|
||||
return [[self shallowCopy] deepen];
|
||||
}
|
||||
|
||||
- shallowCopy
|
||||
{
|
||||
return object_copy(self);
|
||||
}
|
||||
|
||||
- deepen
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
- deepCopy
|
||||
{
|
||||
return [self copy];
|
||||
}
|
||||
|
||||
- (Class)class
|
||||
{
|
||||
return object_get_class(self);
|
||||
}
|
||||
|
||||
- (Class)superClass
|
||||
{
|
||||
return object_get_super_class(self);
|
||||
}
|
||||
|
||||
- (MetaClass)metaClass
|
||||
{
|
||||
return object_get_meta_class(self);
|
||||
}
|
||||
|
||||
- (const char *)name
|
||||
{
|
||||
return object_get_class_name(self);
|
||||
}
|
||||
|
||||
- self
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
- (unsigned int)hash
|
||||
{
|
||||
return (size_t)self;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:anObject
|
||||
{
|
||||
return self==anObject;
|
||||
}
|
||||
|
||||
- (int)compare:(id)anotherObject;
|
||||
{
|
||||
if ([self isEqual:anotherObject])
|
||||
return 0;
|
||||
// Ordering objects by their address is pretty useless,
|
||||
// so subclasses should override this is some useful way.
|
||||
else if ((id)self > anotherObject)
|
||||
return 1;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
- (BOOL)isMetaClass
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)isClass
|
||||
{
|
||||
return object_is_class(self);
|
||||
}
|
||||
|
||||
- (BOOL)isInstance
|
||||
{
|
||||
return object_is_instance(self);
|
||||
}
|
||||
|
||||
- (BOOL)isKindOf:(Class)aClassObject
|
||||
{
|
||||
Class class;
|
||||
|
||||
for (class = self->isa; class!=Nil; class = class_get_super_class(class))
|
||||
if (class==aClassObject)
|
||||
return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)isMemberOf:(Class)aClassObject
|
||||
{
|
||||
return self->isa==aClassObject;
|
||||
}
|
||||
|
||||
- (BOOL)isKindOfClassNamed:(const char *)aClassName
|
||||
{
|
||||
Class class;
|
||||
|
||||
if (aClassName!=NULL)
|
||||
for (class = self->isa; class!=Nil; class = class_get_super_class(class))
|
||||
if (!strcmp(class_get_class_name(class), aClassName))
|
||||
return YES;
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)isMemberOfClassNamed:(const char *)aClassName
|
||||
{
|
||||
return ((aClassName!=NULL)
|
||||
&&!strcmp(class_get_class_name(self->isa), aClassName));
|
||||
}
|
||||
|
||||
BOOL class_respondsToSelector(Class, SEL);
|
||||
+ (BOOL)instancesRespondTo:(SEL)aSel
|
||||
{
|
||||
return class_respondsToSelector(self, aSel);
|
||||
}
|
||||
|
||||
- (BOOL)respondsTo:(SEL)aSel
|
||||
{
|
||||
return class_respondsToSelector(isa, aSel);
|
||||
}
|
||||
|
||||
IMP class_getMethodImplementation(Class cls, SEL name);
|
||||
+ (IMP)instanceMethodFor:(SEL)aSel
|
||||
{
|
||||
return class_getMethodImplementation(self, aSel);
|
||||
}
|
||||
|
||||
// Indicates if the receiving class or instance conforms to the given protocol
|
||||
// not usually overridden by subclasses
|
||||
//
|
||||
// Modified 9/5/94 to always search the class object's protocol list, rather
|
||||
// than the meta class.
|
||||
|
||||
+ (BOOL) conformsTo: (Protocol*)aProtocol
|
||||
{
|
||||
size_t i;
|
||||
struct objc_protocol_list* proto_list;
|
||||
id parent;
|
||||
|
||||
for (proto_list = ((Class)self)->protocols;
|
||||
proto_list; proto_list = proto_list->next)
|
||||
{
|
||||
for (i=0; i < proto_list->count; i++)
|
||||
{
|
||||
if ([proto_list->list[i] conformsTo: aProtocol])
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
if ((parent = [self superClass]))
|
||||
return [parent conformsTo: aProtocol];
|
||||
else
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL) conformsTo: (Protocol*)aProtocol
|
||||
{
|
||||
return [[self class] conformsTo:aProtocol];
|
||||
}
|
||||
|
||||
- (IMP)methodFor:(SEL)aSel
|
||||
{
|
||||
return class_getMethodImplementation(isa, aSel);
|
||||
}
|
||||
|
||||
struct objc_method *class_getInstanceMethod(Class aClass, SEL aSelector);
|
||||
+ (struct objc_method_description *)descriptionForInstanceMethod:(SEL)aSel
|
||||
{
|
||||
return ((struct objc_method_description *)
|
||||
class_getInstanceMethod(self, aSel));
|
||||
}
|
||||
|
||||
struct objc_method *class_getClassMethod(Class aClass, SEL aSelector);
|
||||
- (struct objc_method_description *)descriptionForMethod:(SEL)aSel
|
||||
{
|
||||
return ((struct objc_method_description *)
|
||||
(object_is_instance(self)
|
||||
?class_getInstanceMethod(self->isa, aSel)
|
||||
:class_getClassMethod(self->isa, aSel)));
|
||||
}
|
||||
|
||||
- perform:(SEL)aSel
|
||||
{
|
||||
IMP msg = objc_msg_lookup(self, aSel);
|
||||
if (!msg)
|
||||
return [self error:"invalid selector passed to %s", sel_get_name(_cmd)];
|
||||
return (*msg)(self, aSel);
|
||||
}
|
||||
|
||||
- perform:(SEL)aSel with:anObject
|
||||
{
|
||||
IMP msg = objc_msg_lookup(self, aSel);
|
||||
if (!msg)
|
||||
return [self error:"invalid selector passed to %s", sel_get_name(_cmd)];
|
||||
return (*msg)(self, aSel, anObject);
|
||||
}
|
||||
|
||||
- perform:(SEL)aSel with:anObject1 with:anObject2
|
||||
{
|
||||
IMP msg = objc_msg_lookup(self, aSel);
|
||||
if (!msg)
|
||||
return [self error:"invalid selector passed to %s", sel_get_name(_cmd)];
|
||||
return (*msg)(self, aSel, anObject1, anObject2);
|
||||
}
|
||||
|
||||
- (retval_t)forward:(SEL)aSel :(arglist_t)argFrame
|
||||
{
|
||||
(void) argFrame; /* UNUSED */
|
||||
return (retval_t)[self doesNotRecognize: aSel];
|
||||
}
|
||||
|
||||
- (retval_t)performv:(SEL)aSel :(arglist_t)argFrame
|
||||
{
|
||||
return objc_msg_sendv(self, aSel, argFrame);
|
||||
}
|
||||
|
||||
+ poseAs:(Class)aClassObject
|
||||
{
|
||||
return class_pose_as(self, aClassObject);
|
||||
}
|
||||
|
||||
- (Class)transmuteClassTo:(Class)aClassObject
|
||||
{
|
||||
if (object_is_instance(self))
|
||||
if (class_is_class(aClassObject))
|
||||
if (class_get_instance_size(aClassObject)==class_get_instance_size(isa))
|
||||
if ([self isKindOf:aClassObject])
|
||||
{
|
||||
Class old_isa = isa;
|
||||
isa = aClassObject;
|
||||
return old_isa;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- subclassResponsibility:(SEL)aSel
|
||||
{
|
||||
return [self error:"subclass should override %s", sel_get_name(aSel)];
|
||||
}
|
||||
|
||||
- notImplemented:(SEL)aSel
|
||||
{
|
||||
return [self error:"method %s not implemented", sel_get_name(aSel)];
|
||||
}
|
||||
|
||||
- shouldNotImplement:(SEL)aSel
|
||||
{
|
||||
return [self error:"%s should not implement %s",
|
||||
object_get_class_name(self), sel_get_name(aSel)];
|
||||
}
|
||||
|
||||
- doesNotRecognize:(SEL)aSel
|
||||
{
|
||||
return [self error:"%s does not recognize %s",
|
||||
object_get_class_name(self), sel_get_name(aSel)];
|
||||
}
|
||||
|
||||
- error:(const char *)aString, ...
|
||||
{
|
||||
#define FMT "error: %s (%s)\n%s\n"
|
||||
char fmt[(strlen((char*)FMT)+strlen((char*)object_get_class_name(self))
|
||||
+((aString!=NULL)?strlen((char*)aString):0)+8)];
|
||||
va_list ap;
|
||||
|
||||
sprintf(fmt, FMT, object_get_class_name(self),
|
||||
object_is_instance(self)?"instance":"class",
|
||||
(aString!=NULL)?aString:"");
|
||||
va_start(ap, aString);
|
||||
objc_verror(self, OBJC_ERR_UNKNOWN, fmt, ap);
|
||||
va_end(ap);
|
||||
return nil;
|
||||
#undef FMT
|
||||
}
|
||||
|
||||
+ (int)version
|
||||
{
|
||||
return class_get_version(self);
|
||||
}
|
||||
|
||||
+ setVersion:(int)aVersion
|
||||
{
|
||||
class_set_version(self, aVersion);
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
long objc_get_stream_class_version (TypedStream* stream, Class class)
|
||||
{
|
||||
return class_get_version(class);
|
||||
}
|
198
Protocol.m
198
Protocol.m
@ -1,198 +0,0 @@
|
||||
/* This file contains the implementation of class Protocol.
|
||||
Copyright (C) 1993, 2004, 2009 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
Under Section 7 of GPL version 3, you are granted additional
|
||||
permissions described in the GCC Runtime Library Exception, version
|
||||
3.1, as published by the Free Software Foundation.
|
||||
|
||||
You should have received a copy of the GNU General Public License and
|
||||
a copy of the GCC Runtime Library Exception along with this program;
|
||||
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "objc/Protocol.h"
|
||||
#include "objc/objc-api.h"
|
||||
|
||||
/* Method description list */
|
||||
struct objc_method_description_list {
|
||||
int count;
|
||||
struct objc_method_description list[1];
|
||||
};
|
||||
|
||||
@interface Protocol2 : Protocol
|
||||
{
|
||||
struct objc_method_description_list *optional_instance_methods, *optional_class_methods;
|
||||
struct objc_property_list *properties, *optional_properties;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation Protocol
|
||||
+ (void)load
|
||||
{
|
||||
__CLS_INFO((Class)self) &= ~_CLS_PLANE_AWARE;
|
||||
}
|
||||
|
||||
/* Obtaining attributes intrinsic to the protocol */
|
||||
|
||||
- (const char *)name
|
||||
{
|
||||
return protocol_name;
|
||||
}
|
||||
|
||||
/* Testing protocol conformance */
|
||||
|
||||
- (BOOL) conformsTo: (Protocol *)aProtocolObject
|
||||
{
|
||||
size_t i;
|
||||
struct objc_protocol_list* proto_list;
|
||||
|
||||
if (aProtocolObject == nil)
|
||||
return NO;
|
||||
|
||||
if (!strcmp(aProtocolObject->protocol_name, self->protocol_name))
|
||||
return YES;
|
||||
|
||||
for (proto_list = protocol_list; proto_list; proto_list = proto_list->next)
|
||||
{
|
||||
for (i=0; i < proto_list->count; i++)
|
||||
{
|
||||
if ([proto_list->list[i] conformsTo: aProtocolObject])
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
/* Looking up information specific to a protocol */
|
||||
|
||||
- (struct objc_method_description *) descriptionForInstanceMethod:(SEL)aSel
|
||||
{
|
||||
int i;
|
||||
struct objc_protocol_list* proto_list;
|
||||
const char* name = sel_get_name (aSel);
|
||||
struct objc_method_description *result;
|
||||
|
||||
if (instance_methods)
|
||||
for (i = 0; i < instance_methods->count; i++)
|
||||
{
|
||||
if (!strcmp ((char*)instance_methods->list[i].name, name))
|
||||
return &(instance_methods->list[i]);
|
||||
}
|
||||
|
||||
for (proto_list = protocol_list; proto_list; proto_list = proto_list->next)
|
||||
{
|
||||
size_t j;
|
||||
for (j=0; j < proto_list->count; j++)
|
||||
{
|
||||
if ((result = [proto_list->list[j]
|
||||
descriptionForInstanceMethod: aSel]))
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
- (struct objc_method_description *) descriptionForClassMethod:(SEL)aSel;
|
||||
{
|
||||
int i;
|
||||
struct objc_protocol_list* proto_list;
|
||||
const char* name = sel_get_name (aSel);
|
||||
struct objc_method_description *result;
|
||||
|
||||
if (class_methods)
|
||||
for (i = 0; i < class_methods->count; i++)
|
||||
{
|
||||
if (!strcmp ((char*)class_methods->list[i].name, name))
|
||||
return &(class_methods->list[i]);
|
||||
}
|
||||
|
||||
for (proto_list = protocol_list; proto_list; proto_list = proto_list->next)
|
||||
{
|
||||
size_t j;
|
||||
for (j=0; j < proto_list->count; j++)
|
||||
{
|
||||
if ((result = [proto_list->list[j]
|
||||
descriptionForClassMethod: aSel]))
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
- (unsigned) hash
|
||||
{
|
||||
/* Compute a hash of the protocol_name; use the same hash algorithm
|
||||
* that we use for class names; protocol names and class names are
|
||||
* somewhat similar types of string spaces.
|
||||
*/
|
||||
int hash = 0, index;
|
||||
|
||||
for (index = 0; protocol_name[index] != '\0'; index++)
|
||||
{
|
||||
hash = (hash << 4) ^ (hash >> 28) ^ protocol_name[index];
|
||||
}
|
||||
|
||||
hash = (hash ^ (hash >> 10) ^ (hash >> 20));
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/*
|
||||
* Equality between formal protocols is only formal (nothing to do
|
||||
* with actually checking the list of methods they have!). Two formal
|
||||
* Protocols are equal if and only if they have the same name.
|
||||
*
|
||||
* Please note (for comparisons with other implementations) that
|
||||
* checking the names is equivalent to checking that Protocol A
|
||||
* conforms to Protocol B and Protocol B conforms to Protocol A,
|
||||
* because this happens iff they have the same name. If they have
|
||||
* different names, A conforms to B if and only if A includes B, but
|
||||
* the situation where A includes B and B includes A is a circular
|
||||
* dependency between Protocols which is forbidden by the compiler, so
|
||||
* A conforms to B and B conforms to A with A and B having different
|
||||
* names is an impossible case.
|
||||
*/
|
||||
- (BOOL) isEqual: (id)obj
|
||||
{
|
||||
if (obj == self)
|
||||
return YES;
|
||||
|
||||
if ([obj isKindOf: [Protocol class]])
|
||||
{
|
||||
if (strcmp (protocol_name, ((Protocol *)obj)->protocol_name) == 0)
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
@end
|
||||
|
||||
/**
|
||||
* Objective-C 2 protocol objects are opaque.
|
||||
*/
|
||||
@implementation Protocol2 @end
|
||||
|
||||
/**
|
||||
* This class exists for the sole reason that the legacy GNU ABI did not
|
||||
* provide a way of registering protocols with the runtime. With the new ABI,
|
||||
* every protocol in a compilation unit that is not referenced should be added
|
||||
* in a category on this class. This ensures that the runtime sees every
|
||||
* protocol at least once and can perform uniquing.
|
||||
*/
|
||||
@interface __ObjC_Protocol_Holder_Ugly_Hack : Object @end
|
||||
@implementation __ObjC_Protocol_Holder_Ugly_Hack @end
|
@ -24,6 +24,7 @@ static void load_category(struct objc_category *cat, struct objc_class *class)
|
||||
{
|
||||
register_methods(class, cat->instance_methods);
|
||||
register_methods(class->isa, cat->class_methods);
|
||||
//fprintf(stderr, "Loading %s (%s)\n", cat->class_name, cat->name);
|
||||
|
||||
if (cat->protocols)
|
||||
{
|
||||
@ -36,11 +37,13 @@ static void load_category(struct objc_category *cat, struct objc_class *class)
|
||||
static BOOL try_load_category(struct objc_category *cat)
|
||||
{
|
||||
Class class = (Class)objc_getClass(cat->class_name);
|
||||
//fprintf(stderr, "Trying to load %s (%s)\n", cat->class_name, cat->name);
|
||||
if (Nil != class)
|
||||
{
|
||||
load_category(cat, class);
|
||||
return YES;
|
||||
}
|
||||
//fprintf(stderr, "waiting to load %s (%s)\n", cat->class_name, cat->name);
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
10
class.h
10
class.h
@ -159,9 +159,19 @@ static inline void objc_set_class_flag(struct objc_class *aClass,
|
||||
{
|
||||
aClass->info |= (long)flag;
|
||||
}
|
||||
static inline void objc_clear_class_flag(struct objc_class *aClass,
|
||||
enum objc_class_flags flag)
|
||||
{
|
||||
aClass->info &= ~(long)flag;
|
||||
}
|
||||
static inline BOOL objc_test_class_flag(struct objc_class *aClass,
|
||||
enum objc_class_flags flag)
|
||||
{
|
||||
return aClass->info & (long)flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a class to the class table.
|
||||
*/
|
||||
void class_table_insert(Class class);
|
||||
#endif //__OBJC_CLASS_H_INCLUDED
|
||||
|
@ -259,6 +259,7 @@ void __objc_resolve_class_links(void)
|
||||
objc_resolve_class_links();
|
||||
}
|
||||
|
||||
/*
|
||||
// FIXME: Remove this once all uses of it in the runtime have been removed
|
||||
void __objc_add_class_to_hash(Class class)
|
||||
{
|
||||
@ -271,6 +272,7 @@ void __objc_add_class_to_hash(Class class)
|
||||
// class number though, so we don't bother.
|
||||
class_table_insert (class);
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Loads a class. This function assumes that the runtime mutex is locked.
|
||||
|
17
dtable.c
17
dtable.c
@ -32,6 +32,7 @@ static void collectMethodsForMethodListToSparseArray(
|
||||
}
|
||||
for (unsigned i=0 ; i<list->count ; i++)
|
||||
{
|
||||
//fprintf(stderr, "Adding method %s (%d)\n", sel_getName(list->methods[i].selector), PTR_TO_IDX(list->methods[i].selector->name));
|
||||
SparseArrayInsert(sarray, PTR_TO_IDX(list->methods[i].selector->name),
|
||||
(void*)&list->methods[i]);
|
||||
}
|
||||
@ -48,6 +49,7 @@ static BOOL installMethodInDtable(Class class,
|
||||
struct objc_slot *slot = SparseArrayLookup(dtable, sel_id);
|
||||
if (NULL != slot)
|
||||
{
|
||||
//fprintf(stderr, "Slot already exists...\n");
|
||||
// If this method is the one already installed, pretend to install it again.
|
||||
if (slot->method == method->imp) { return NO; }
|
||||
|
||||
@ -59,7 +61,7 @@ static BOOL installMethodInDtable(Class class,
|
||||
// Don't replace methods if we're not meant to (if they're from
|
||||
// later in a method list, for example)
|
||||
if (!replaceExisting) { return NO; }
|
||||
//fprintf(stderr, "Replacing method %p %s in %s with %x\n", slot->method, sel_get_name(method->selector), class->name, method->imp);
|
||||
//fprintf(stderr, "Replacing method %p %s in %s with %p\n", slot->method, sel_getName(method->selector), class->name, method->imp);
|
||||
slot->method = method->imp;
|
||||
return YES;
|
||||
}
|
||||
@ -71,19 +73,21 @@ static BOOL installMethodInDtable(Class class,
|
||||
Nil != installedFor ;
|
||||
installedFor = installedFor->super_class)
|
||||
{
|
||||
if (installedFor == owner) {
|
||||
//fprintf(stderr, "Not installing %s from %s in %s - already overridden from %s\n", sel_get_name(method->selector), owner->name, class->name, slot->owner->name);
|
||||
return NO; }
|
||||
if (installedFor == owner)
|
||||
{
|
||||
//fprintf(stderr, "Not installing %s from %s in %s - already overridden from %s\n", sel_getName(method->selector), owner->name, class->name, slot->owner->name);
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
struct objc_slot *oldSlot = slot;
|
||||
//fprintf(stderr, "Installing method %p (%d) %s in %s (previous slot owned by %s)\n", method->imp, sel_id, sel_get_name(method->selector), class->name, slot? oldSlot->owner->name: "");
|
||||
//fprintf(stderr, "Installing method %p (%d) %s in %s (previous slot owned by %s)\n", method->imp, sel_id, sel_getName(method->selector), class->name, slot? oldSlot->owner->name: "(no one)");
|
||||
slot = new_slot_for_method_in_class((void*)method, owner);
|
||||
SparseArrayInsert(dtable, sel_id, slot);
|
||||
// Invalidate the old slot, if there is one.
|
||||
if (NULL != oldSlot)
|
||||
{
|
||||
//fprintf(stderr, "Overriding method %p %s from %s in %s with %x\n", slot->method, sel_get_name(method->selector), oldSlot->owner->name, class->name, method->imp);
|
||||
//fprintf(stderr, "Overriding method %p %s from %s in %s with %x\n", slot->method, sel_getName(method->selector), oldSlot->owner->name, class->name, method->imp);
|
||||
oldSlot->version++;
|
||||
}
|
||||
return YES;
|
||||
@ -140,6 +144,7 @@ void objc_update_dtable_for_class(Class cls)
|
||||
|
||||
LOCK_UNTIL_RETURN(__objc_runtime_mutex);
|
||||
|
||||
//fprintf(stderr, "Adding methods to %s\n", cls->name);
|
||||
SparseArray *methods = SparseArrayNewWithDepth(dtable_depth);
|
||||
collectMethodsForMethodListToSparseArray((void*)cls->methods, methods);
|
||||
installMethodsInClass(cls, cls, methods, YES);
|
||||
|
12
dtable.h
12
dtable.h
@ -25,6 +25,9 @@ typedef struct _InitializingDtable
|
||||
extern InitializingDtable *temporary_dtables;
|
||||
mutex_t initialize_lock;
|
||||
|
||||
/**
|
||||
* Returns whether a class has an installed dtable.
|
||||
*/
|
||||
static inline int classHasInstalledDtable(struct objc_class *cls)
|
||||
{
|
||||
return ((void*)cls->dtable != __objc_uninstalled_dtable);
|
||||
@ -69,7 +72,16 @@ static inline SparseArray *dtable_for_class(Class cls)
|
||||
return dtable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a class has had a dtable created. The dtable may be
|
||||
* installed, or stored in the look-aside buffer.
|
||||
*/
|
||||
static inline int classHasDtable(struct objc_class *cls)
|
||||
{
|
||||
return (dtable_for_class(cls) != __objc_uninstalled_dtable);
|
||||
}
|
||||
/**
|
||||
* Updates the dtable for a class and its subclasses. Must be called after
|
||||
* modifying a class's method list.
|
||||
*/
|
||||
void objc_update_dtable_for_class(Class);
|
||||
|
36
legacy_malloc.c
Normal file
36
legacy_malloc.c
Normal file
@ -0,0 +1,36 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
void *valloc(size_t);
|
||||
|
||||
// Stubs that just call the libc implementations when you call these.
|
||||
|
||||
void *objc_malloc(size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void *objc_atomic_malloc(size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void *objc_valloc(size_t size)
|
||||
{
|
||||
return valloc(size);
|
||||
}
|
||||
|
||||
void *objc_realloc(void *mem, size_t size)
|
||||
{
|
||||
return realloc(mem, size);
|
||||
}
|
||||
|
||||
void * objc_calloc(size_t nelem, size_t size)
|
||||
{
|
||||
return calloc(nelem, size);
|
||||
}
|
||||
|
||||
void objc_free(void *mem)
|
||||
{
|
||||
free(mem);
|
||||
}
|
||||
|
45
protocol.c
45
protocol.c
@ -1,6 +1,7 @@
|
||||
#include "objc/runtime.h"
|
||||
#include "protocol.h"
|
||||
#include "properties.h"
|
||||
#include "class.h"
|
||||
#include "lock.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
@ -218,12 +219,54 @@ Protocol *objc_getProtocol(const char *name)
|
||||
return (Protocol*)protocol_for_name(name);
|
||||
}
|
||||
|
||||
BOOL protocol_conformsToProtocol(Protocol *p, Protocol *other)
|
||||
BOOL protocol_conformsToProtocol(Protocol *p1, Protocol *p2)
|
||||
{
|
||||
// A protocol trivially conforms to itself
|
||||
if (strcmp(p1->name, p2->name) == 0) { return YES; }
|
||||
|
||||
for (struct objc_protocol_list *list = p1->protocol_list ;
|
||||
list != NULL ; list = list->next)
|
||||
{
|
||||
for (int i=0 ; i<list->count ; i++)
|
||||
{
|
||||
fprintf(stderr, "recursively checking %s\n", list->list[i]->name);
|
||||
if (strcmp(list->list[i]->name, p2->name) == 0)
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
if (protocol_conformsToProtocol((Protocol*)list->list[i], p2))
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
BOOL class_conformsToProtocol(Class cls, Protocol *protocol)
|
||||
{
|
||||
fprintf(stderr, "Testing if %s conforms to %s\n", cls->name, protocol->name);
|
||||
while (cls)
|
||||
{
|
||||
for (struct objc_protocol_list *protocols = cls->protocols;
|
||||
protocols != NULL ; protocols = protocols->next)
|
||||
{
|
||||
for (int i=0 ; i<protocols->count ; i++)
|
||||
{
|
||||
Protocol *p1 = (Protocol*)protocols->list[i];
|
||||
fprintf(stderr, "checking %s\n", p1->name);
|
||||
if (protocol_conformsToProtocol(p1, protocol))
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
cls = cls->super_class;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
//FIXME!!!!
|
||||
struct objc_method_description *protocol_copyMethodDescriptionList(Protocol *p,
|
||||
BOOL isRequiredMethod, BOOL isInstanceMethod, unsigned int *count)
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "selector.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
struct objc_method_description_list
|
||||
{
|
||||
@ -20,10 +21,12 @@ struct objc_method_description_list
|
||||
*/
|
||||
#ifdef __OBJC__
|
||||
@interface Protocol
|
||||
{
|
||||
@public
|
||||
#else
|
||||
struct objc_protocol
|
||||
#endif
|
||||
{
|
||||
#endif
|
||||
/** Class pointer. */
|
||||
id isa;
|
||||
/**
|
||||
@ -51,8 +54,9 @@ struct objc_protocol
|
||||
#endif
|
||||
|
||||
#ifdef __OBJC__
|
||||
@interface Protocol2
|
||||
@interface Protocol2 : Protocol
|
||||
{
|
||||
@public
|
||||
#else
|
||||
typedef struct objc_protocol2
|
||||
{
|
||||
|
313
runtime.c
313
runtime.c
@ -1,4 +1,11 @@
|
||||
#include "objc/runtime.h"
|
||||
#include "selector.h"
|
||||
#include "class.h"
|
||||
#include "protocol.h"
|
||||
#include "ivar.h"
|
||||
#include "method_list.h"
|
||||
#include "lock.h"
|
||||
#include "dtable.h"
|
||||
|
||||
/* Make glibc export strdup() */
|
||||
|
||||
@ -6,72 +13,12 @@
|
||||
#define __USE_BSD 1
|
||||
#endif
|
||||
|
||||
#undef __objc_INCLUDE_GNU
|
||||
#undef __thread_INCLUDE_GNU
|
||||
#undef __objc_api_INCLUDE_GNU
|
||||
#undef __encoding_INCLUDE_GNU
|
||||
|
||||
#define objc_object objc_object_gnu
|
||||
#define id object_ptr_gnu
|
||||
#define IMP objc_imp_gnu
|
||||
#define Method objc_method_gnu
|
||||
|
||||
#define object_copy gnu_object_copy
|
||||
#define object_dispose gnu_object_dispose
|
||||
#define objc_super gnu_objc_super
|
||||
#define objc_msg_lookup gnu_objc_msg_lookup
|
||||
#define objc_msg_lookup_super gnu_objc_msg_lookup_super
|
||||
#define BOOL GNU_BOOL
|
||||
#define SEL GNU_SEL
|
||||
#define Protocol GNU_Protocol
|
||||
#define Class GNU_Class
|
||||
|
||||
#undef YES
|
||||
#undef NO
|
||||
#undef Nil
|
||||
#undef nil
|
||||
|
||||
#include <objc/objc.h>
|
||||
#include <objc/objc-api.h>
|
||||
#undef GNU_BOOL
|
||||
#include <objc/encoding.h>
|
||||
#undef Class
|
||||
#undef Protocol
|
||||
#undef SEL
|
||||
#undef objc_msg_lookup
|
||||
#undef objc_msg_lookup_super
|
||||
#undef objc_super
|
||||
#undef Method
|
||||
#undef IMP
|
||||
#undef id
|
||||
#undef objc_object
|
||||
|
||||
// Reinstall definitions.
|
||||
#undef YES
|
||||
#undef NO
|
||||
#undef Nil
|
||||
#undef nil
|
||||
#define YES ((BOOL)1)
|
||||
#define NO ((BOOL)0)
|
||||
#define nil ((id)_OBJC_NULL_PTR)
|
||||
#define Nil ((Class)_OBJC_NULL_PTR)
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
/**
|
||||
* Private runtime function for updating a dtable.
|
||||
*/
|
||||
void __objc_update_dispatch_table_for_class(Class);
|
||||
/**
|
||||
* Runtime library constant for uninitialized dispatch table.
|
||||
*/
|
||||
extern struct sarray *__objc_uninstalled_dtable;
|
||||
/**
|
||||
* Mutex used to protect the ObjC runtime library data structures.
|
||||
*/
|
||||
extern objc_mutex_t __objc_runtime_mutex;
|
||||
Class objc_next_class(void*);
|
||||
|
||||
/**
|
||||
* Looks up the instance method in a specific class, without recursing into
|
||||
@ -80,12 +27,12 @@ extern objc_mutex_t __objc_runtime_mutex;
|
||||
static Method class_getInstanceMethodNonrecursive(Class aClass, SEL aSelector)
|
||||
{
|
||||
for (struct objc_method_list *methods = aClass->methods;
|
||||
methods != NULL ; methods = methods->method_next)
|
||||
methods != NULL ; methods = methods->next)
|
||||
{
|
||||
for (int i=0 ; i<methods->method_count ; i++)
|
||||
for (int i=0 ; i<methods->count ; i++)
|
||||
{
|
||||
Method_t method = &methods->method_list[i];
|
||||
if (method->method_name->sel_id == aSelector->sel_id)
|
||||
Method method = &methods->methods[i];
|
||||
if (method->selector->name == aSelector->name)
|
||||
{
|
||||
return method;
|
||||
}
|
||||
@ -103,87 +50,86 @@ static void objc_updateDtableForClassContainingMethod(Method m)
|
||||
{
|
||||
if (class_getInstanceMethodNonrecursive(nextClass, sel) == m)
|
||||
{
|
||||
__objc_update_dispatch_table_for_class(nextClass);
|
||||
objc_update_dtable_for_class(nextClass);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOL
|
||||
class_addIvar(Class cls, const char *name,
|
||||
size_t size, uint8_t alignment, const char *types)
|
||||
BOOL class_addIvar(Class cls, const char *name, size_t size, uint8_t alignment,
|
||||
const char *types)
|
||||
{
|
||||
struct objc_ivar_list *ivarlist;
|
||||
unsigned off;
|
||||
Ivar ivar;
|
||||
// You can't add ivars to resolved classes (note: You ought to be able to
|
||||
// add them to classes that currently have no instances)
|
||||
if (objc_test_class_flag(cls, objc_class_flag_resolved))
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (CLS_ISRESOLV(cls) || CLS_ISMETA(cls))
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
if (class_getInstanceVariable(cls, name) != NULL)
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (class_getInstanceVariable(cls, name) != NULL)
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
struct objc_ivar_list *ivarlist = cls->ivars;
|
||||
|
||||
ivarlist = cls->ivars;
|
||||
if (NULL == ivarlist)
|
||||
{
|
||||
cls->ivars = malloc(sizeof(struct objc_ivar_list));
|
||||
cls->ivars->count = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ivarlist->count++;
|
||||
// objc_ivar_list contains one ivar. Others follow it.
|
||||
cls->ivars = realloc(ivarlist, sizeof(struct objc_ivar_list) +
|
||||
(ivarlist->count - 1) * sizeof(struct objc_ivar));
|
||||
}
|
||||
Ivar ivar = &cls->ivars->ivar_list[cls->ivars->count - 1];
|
||||
ivar->name = strdup(name);
|
||||
ivar->type = strdup(types);
|
||||
// Round up the offset of the ivar so it is correctly aligned.
|
||||
long offset = cls->instance_size >> alignment;
|
||||
|
||||
if (NULL == ivarlist)
|
||||
{
|
||||
cls->ivars = objc_malloc(sizeof(struct objc_ivar_list));
|
||||
cls->ivars->ivar_count = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ivarlist->ivar_count++;
|
||||
// objc_ivar_list contains one ivar. Others follow it.
|
||||
cls->ivars = objc_realloc(ivarlist, sizeof(struct objc_ivar_list)
|
||||
+ (ivarlist->ivar_count -
|
||||
1) * sizeof(struct objc_ivar));
|
||||
}
|
||||
if (offset << alignment != cls->instance_size)
|
||||
{
|
||||
offset = (offset+ 1) << alignment;
|
||||
}
|
||||
|
||||
ivar = &cls->ivars->ivar_list[cls->ivars->ivar_count - 1];
|
||||
ivar->ivar_name = strdup(name);
|
||||
ivar->ivar_type = strdup(types);
|
||||
// Round up the offset of the ivar so it is correctly aligned.
|
||||
off = cls->instance_size >> alignment;
|
||||
if (off << alignment != cls->instance_size)
|
||||
off = (off + 1) << alignment;
|
||||
ivar->ivar_offset = off;
|
||||
// Increase the instance size to make space for this.
|
||||
cls->instance_size = ivar->ivar_offset + size;
|
||||
return YES;
|
||||
ivar->offset = offset;
|
||||
// Increase the instance size to make space for this.
|
||||
cls->instance_size = ivar->offset + size;
|
||||
return YES;
|
||||
}
|
||||
|
||||
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
|
||||
{
|
||||
const char *methodName = sel_get_name(name);
|
||||
const char *methodName = sel_getName(name);
|
||||
struct objc_method_list *methods;
|
||||
for (methods=cls->methods; methods!=NULL ; methods=methods->method_next)
|
||||
for (methods=cls->methods; methods!=NULL ; methods=methods->next)
|
||||
{
|
||||
for (int i=0 ; i<methods->method_count ; i++)
|
||||
for (int i=0 ; i<methods->count ; i++)
|
||||
{
|
||||
Method_t method = &methods->method_list[i];
|
||||
if (strcmp(sel_get_name(method->method_name), methodName) == 0)
|
||||
Method method = &methods->methods[i];
|
||||
if (strcmp(sel_getName(method->selector), methodName) == 0)
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
methods = objc_malloc(sizeof(struct objc_method_list));
|
||||
methods->method_next = cls->methods;
|
||||
methods = malloc(sizeof(struct objc_method_list));
|
||||
methods->next = cls->methods;
|
||||
cls->methods = methods;
|
||||
|
||||
methods->method_count = 1;
|
||||
methods->method_list[0].method_name = sel_register_typed_name(methodName, types);
|
||||
methods->method_list[0].method_types = strdup(types);
|
||||
methods->method_list[0].method_imp = (objc_imp_gnu)imp;
|
||||
methods->count = 1;
|
||||
methods->methods[0].selector = sel_registerTypedName_np(methodName, types);
|
||||
methods->methods[0].types = strdup(types);
|
||||
methods->methods[0].imp = imp;
|
||||
|
||||
if (CLS_ISRESOLV(cls))
|
||||
if (objc_test_class_flag(cls, objc_class_flag_resolved))
|
||||
{
|
||||
__objc_update_dispatch_table_for_class(cls);
|
||||
objc_update_dtable_for_class(cls);
|
||||
}
|
||||
|
||||
return YES;
|
||||
@ -193,33 +139,15 @@ BOOL class_addProtocol(Class cls, Protocol *protocol)
|
||||
{
|
||||
if (class_conformsToProtocol(cls, protocol)) { return NO; }
|
||||
struct objc_protocol_list *protocols = cls->protocols;
|
||||
protocols = objc_malloc(sizeof(struct objc_protocol_list));
|
||||
protocols = malloc(sizeof(struct objc_protocol_list));
|
||||
if (protocols == NULL) { return NO; }
|
||||
protocols->next = cls->protocols;
|
||||
protocols->count = 1;
|
||||
protocols->list[0] = protocol;
|
||||
protocols->list[0] = (Protocol2*)protocol;
|
||||
cls->protocols = protocols;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
BOOL class_conformsToProtocol(Class cls, Protocol *protocol)
|
||||
{
|
||||
for (struct objc_protocol_list *protocols = cls->protocols;
|
||||
protocols != NULL ; protocols = protocols->next)
|
||||
{
|
||||
for (int i=0 ; i<protocols->count ; i++)
|
||||
{
|
||||
if (strcmp(protocols->list[i]->protocol_name,
|
||||
protocol->protocol_name) == 0)
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
Ivar *
|
||||
class_copyIvarList(Class cls, unsigned int *outCount)
|
||||
{
|
||||
@ -230,7 +158,7 @@ class_copyIvarList(Class cls, unsigned int *outCount)
|
||||
|
||||
if (ivarlist != NULL)
|
||||
{
|
||||
count = ivarlist->ivar_count;
|
||||
count = ivarlist->count;
|
||||
}
|
||||
if (outCount != NULL)
|
||||
{
|
||||
@ -244,7 +172,7 @@ class_copyIvarList(Class cls, unsigned int *outCount)
|
||||
list = malloc((count + 1) * sizeof(struct objc_ivar *));
|
||||
list[count] = NULL;
|
||||
count = 0;
|
||||
for (index = 0; index < ivarlist->ivar_count; index++)
|
||||
for (index = 0; index < ivarlist->count; index++)
|
||||
{
|
||||
list[count++] = &ivarlist->ivar_list[index];
|
||||
}
|
||||
@ -259,9 +187,9 @@ class_copyMethodList(Class cls, unsigned int *outCount)
|
||||
Method *list;
|
||||
struct objc_method_list *methods;
|
||||
|
||||
for (methods = cls->methods; methods != NULL; methods = methods->method_next)
|
||||
for (methods = cls->methods; methods != NULL; methods = methods->next)
|
||||
{
|
||||
count += methods->method_count;
|
||||
count += methods->count;
|
||||
}
|
||||
if (outCount != NULL)
|
||||
{
|
||||
@ -275,13 +203,13 @@ class_copyMethodList(Class cls, unsigned int *outCount)
|
||||
list = malloc((count + 1) * sizeof(struct objc_method *));
|
||||
list[count] = NULL;
|
||||
count = 0;
|
||||
for (methods = cls->methods; methods != NULL; methods = methods->method_next)
|
||||
for (methods = cls->methods; methods != NULL; methods = methods->next)
|
||||
{
|
||||
unsigned int index;
|
||||
|
||||
for (index = 0; index < methods->method_count; index++)
|
||||
for (index = 0; index < methods->count; index++)
|
||||
{
|
||||
list[count++] = &methods->method_list[index];
|
||||
list[count++] = &methods->methods[index];
|
||||
}
|
||||
}
|
||||
|
||||
@ -322,7 +250,7 @@ class_copyProtocolList(Class cls, unsigned int *outCount)
|
||||
|
||||
id class_createInstance(Class cls, size_t extraBytes)
|
||||
{
|
||||
id obj = objc_malloc(cls->instance_size + extraBytes);
|
||||
id obj = malloc(cls->instance_size + extraBytes);
|
||||
obj->isa = cls;
|
||||
return obj;
|
||||
}
|
||||
@ -345,7 +273,7 @@ Method class_getInstanceMethod(Class aClass, SEL aSelector)
|
||||
|
||||
Method class_getClassMethod(Class aClass, SEL aSelector)
|
||||
{
|
||||
return class_getInstanceMethod(aClass->class_pointer, aSelector);
|
||||
return class_getInstanceMethod(aClass->isa, aSelector);
|
||||
}
|
||||
|
||||
Ivar class_getClassVariable(Class cls, const char* name)
|
||||
@ -372,11 +300,11 @@ class_getInstanceVariable(Class cls, const char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ivarlist->ivar_count; i++)
|
||||
for (i = 0; i < ivarlist->count; i++)
|
||||
{
|
||||
Ivar ivar = &ivarlist->ivar_list[i];
|
||||
|
||||
if (strcmp(ivar->ivar_name, name) == 0)
|
||||
if (strcmp(ivar->name, name) == 0)
|
||||
{
|
||||
return ivar;
|
||||
}
|
||||
@ -415,7 +343,7 @@ const char * class_getName(Class cls)
|
||||
|
||||
int class_getVersion(Class theClass)
|
||||
{
|
||||
return class_get_version(theClass);
|
||||
return theClass->version;
|
||||
}
|
||||
|
||||
const char *class_getWeakIvarLayout(Class cls)
|
||||
@ -426,7 +354,7 @@ const char *class_getWeakIvarLayout(Class cls)
|
||||
|
||||
BOOL class_isMetaClass(Class cls)
|
||||
{
|
||||
return CLS_ISMETA(cls);
|
||||
return objc_test_class_flag(cls, objc_class_flag_meta);
|
||||
}
|
||||
|
||||
IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)
|
||||
@ -437,12 +365,12 @@ IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)
|
||||
class_addMethod(cls, name, imp, types);
|
||||
return NULL;
|
||||
}
|
||||
IMP old = (IMP)method->method_imp;
|
||||
method->method_imp = (objc_imp_gnu)imp;
|
||||
IMP old = (IMP)method->imp;
|
||||
method->imp = imp;
|
||||
|
||||
if (CLS_ISRESOLV(cls))
|
||||
if (objc_test_class_flag(cls, objc_class_flag_resolved))
|
||||
{
|
||||
__objc_update_dispatch_table_for_class(cls);
|
||||
objc_update_dtable_for_class(cls);
|
||||
}
|
||||
|
||||
return old;
|
||||
@ -453,7 +381,7 @@ void class_setIvarLayout(Class cls, const char *layout)
|
||||
{
|
||||
struct objc_ivar_list *list = (struct objc_ivar_list*)layout;
|
||||
size_t listsize = sizeof(struct objc_ivar_list) +
|
||||
sizeof(struct objc_ivar) * (list->ivar_count - 1);
|
||||
sizeof(struct objc_ivar) * (list->count - 1);
|
||||
cls->ivars = malloc(listsize);
|
||||
memcpy(cls->ivars, list, listsize);
|
||||
}
|
||||
@ -468,7 +396,7 @@ Class class_setSuperclass(Class cls, Class newSuper)
|
||||
|
||||
void class_setVersion(Class theClass, int version)
|
||||
{
|
||||
class_set_version(theClass, version);
|
||||
theClass->version = version;
|
||||
}
|
||||
|
||||
void class_setWeakIvarLayout(Class cls, const char *layout)
|
||||
@ -478,44 +406,44 @@ void class_setWeakIvarLayout(Class cls, const char *layout)
|
||||
|
||||
const char * ivar_getName(Ivar ivar)
|
||||
{
|
||||
return ivar->ivar_name;
|
||||
return ivar->name;
|
||||
}
|
||||
|
||||
ptrdiff_t ivar_getOffset(Ivar ivar)
|
||||
{
|
||||
return ivar->ivar_offset;
|
||||
return ivar->offset;
|
||||
}
|
||||
|
||||
const char * ivar_getTypeEncoding(Ivar ivar)
|
||||
{
|
||||
return ivar->ivar_type;
|
||||
return ivar->type;
|
||||
}
|
||||
|
||||
|
||||
void method_exchangeImplementations(Method m1, Method m2)
|
||||
{
|
||||
IMP tmp = (IMP)m1->method_imp;
|
||||
m1->method_imp = m2->method_imp;
|
||||
m2->method_imp = (objc_imp_gnu)tmp;
|
||||
IMP tmp = (IMP)m1->imp;
|
||||
m1->imp = m2->imp;
|
||||
m2->imp = tmp;
|
||||
objc_updateDtableForClassContainingMethod(m1);
|
||||
objc_updateDtableForClassContainingMethod(m2);
|
||||
}
|
||||
|
||||
IMP method_getImplementation(Method method)
|
||||
{
|
||||
return (IMP)method->method_imp;
|
||||
return (IMP)method->imp;
|
||||
}
|
||||
|
||||
SEL method_getName(Method method)
|
||||
{
|
||||
return (SEL)method->method_name;
|
||||
return (SEL)method->selector;
|
||||
}
|
||||
|
||||
|
||||
IMP method_setImplementation(Method method, IMP imp)
|
||||
{
|
||||
IMP old = (IMP)method->method_imp;
|
||||
method->method_imp = (objc_imp_gnu)old;
|
||||
IMP old = (IMP)method->imp;
|
||||
method->imp = old;
|
||||
objc_updateDtableForClassContainingMethod(method);
|
||||
return old;
|
||||
}
|
||||
@ -535,12 +463,12 @@ static void freeMethodLists(Class aClass)
|
||||
struct objc_method_list *methods = aClass->methods;
|
||||
while(methods != NULL)
|
||||
{
|
||||
for (int i=0 ; i<methods->method_count ; i++)
|
||||
for (int i=0 ; i<methods->count ; i++)
|
||||
{
|
||||
free((void*)methods->method_list[i].method_types);
|
||||
free((void*)methods->methods[i].types);
|
||||
}
|
||||
struct objc_method_list *current = methods;
|
||||
methods = methods->method_next;
|
||||
methods = methods->next;
|
||||
free(current);
|
||||
}
|
||||
}
|
||||
@ -550,11 +478,11 @@ static void freeIvarLists(Class aClass)
|
||||
struct objc_ivar_list *ivarlist = aClass->ivars;
|
||||
if (NULL == ivarlist) { return; }
|
||||
|
||||
for (int i=0 ; i<ivarlist->ivar_count ; i++)
|
||||
for (int i=0 ; i<ivarlist->count ; i++)
|
||||
{
|
||||
Ivar ivar = &ivarlist->ivar_list[i];
|
||||
free((void*)ivar->ivar_type);
|
||||
free((void*)ivar->ivar_name);
|
||||
free((void*)ivar->type);
|
||||
free((void*)ivar->name);
|
||||
}
|
||||
free(ivarlist);
|
||||
}
|
||||
@ -589,10 +517,10 @@ void objc_disposeClassPair(Class cls)
|
||||
Class meta = ((id)cls)->isa;
|
||||
// Remove from the runtime system so nothing tries updating the dtable
|
||||
// while we are freeing the class.
|
||||
objc_mutex_lock(__objc_runtime_mutex);
|
||||
LOCK(__objc_runtime_mutex);
|
||||
safe_remove_from_subclass_list(meta);
|
||||
safe_remove_from_subclass_list(cls);
|
||||
objc_mutex_unlock(__objc_runtime_mutex);
|
||||
UNLOCK(__objc_runtime_mutex);
|
||||
|
||||
// Free the method and ivar lists.
|
||||
freeMethodLists(cls);
|
||||
@ -617,20 +545,22 @@ Class objc_allocateClassPair(Class superclass, const char *name, size_t extraByt
|
||||
Class metaClass = calloc(1, sizeof(struct objc_class));
|
||||
|
||||
// Initialize the metaclass
|
||||
metaClass->class_pointer = superclass->class_pointer->class_pointer;
|
||||
metaClass->super_class = superclass->class_pointer;
|
||||
metaClass->isa = superclass->isa->isa;
|
||||
metaClass->super_class = superclass->isa;
|
||||
metaClass->name = strdup(name);
|
||||
metaClass->info = _CLS_META | _CLS_RUNTIME | _CLS_NEW_ABI;
|
||||
metaClass->info = objc_class_flag_meta | objc_class_flag_user_created |
|
||||
objc_class_flag_new_abi;
|
||||
metaClass->dtable = __objc_uninstalled_dtable;
|
||||
metaClass->instance_size = sizeof(struct objc_class);
|
||||
|
||||
// Set up the new class
|
||||
newClass->class_pointer = metaClass;
|
||||
newClass->isa = metaClass;
|
||||
// Set the superclass pointer to the name. The runtime will fix this when
|
||||
// the class links are resolved.
|
||||
newClass->super_class = (Class)(superclass->name);
|
||||
newClass->name = strdup(name);
|
||||
newClass->info = _CLS_CLASS | _CLS_RUNTIME | _CLS_NEW_ABI;
|
||||
newClass->info = objc_class_flag_class | objc_class_flag_user_created |
|
||||
objc_class_flag_new_abi;
|
||||
newClass->dtable = __objc_uninstalled_dtable;
|
||||
newClass->instance_size = superclass->instance_size;
|
||||
|
||||
@ -642,11 +572,12 @@ Class objc_allocateMetaClass(Class superclass, size_t extraBytes)
|
||||
Class metaClass = calloc(1, sizeof(struct objc_class) + extraBytes);
|
||||
|
||||
// Initialize the metaclass
|
||||
metaClass->class_pointer = superclass->class_pointer;
|
||||
metaClass->super_class = superclass->class_pointer;
|
||||
metaClass->isa = superclass->isa;
|
||||
metaClass->super_class = superclass->isa;
|
||||
metaClass->name = "hidden class"; //strdup(superclass->name);
|
||||
metaClass->info = _CLS_RESOLV | _CLS_INITIALIZED | _CLS_META |
|
||||
_CLS_RUNTIME | _CLS_NEW_ABI;
|
||||
metaClass->info = objc_class_flag_resolved | objc_class_flag_initialized |
|
||||
objc_class_flag_meta | objc_class_flag_user_created |
|
||||
objc_class_flag_new_abi;
|
||||
metaClass->dtable = __objc_uninstalled_dtable;
|
||||
metaClass->instance_size = sizeof(struct objc_class);
|
||||
|
||||
@ -689,16 +620,8 @@ const char *object_getClassName(id obj)
|
||||
return class_getName(object_getClass(obj));
|
||||
}
|
||||
|
||||
void __objc_add_class_to_hash(Class cls);
|
||||
void objc_resolve_class(Class cls);
|
||||
|
||||
void objc_registerClassPair(Class cls)
|
||||
{
|
||||
Class metaClass = cls->class_pointer;
|
||||
// Initialize the dispatch table for the class and metaclass.
|
||||
__objc_update_dispatch_table_for_class(metaClass);
|
||||
__objc_update_dispatch_table_for_class(cls);
|
||||
__objc_add_class_to_hash(cls);
|
||||
objc_resolve_class(cls);
|
||||
|
||||
LOCK_UNTIL_RETURN(__objc_runtime_mutex);
|
||||
class_table_insert(cls);
|
||||
}
|
||||
|
20
sarray2.c
20
sarray2.c
@ -11,7 +11,6 @@ static SparseArray EmptyArray = { 0xff, 0, 0, (void**)&EmptyArrayData};
|
||||
#define MAX_INDEX(sarray) (sarray->mask >> sarray->shift)
|
||||
#define DATA_SIZE(sarray) ((sarray->mask >> sarray->shift) + 1)
|
||||
|
||||
#define fprintf(...)
|
||||
// Tweak this value to trade speed for memory usage. Bigger values use more
|
||||
// memory, but give faster lookups.
|
||||
#define base_shift 8
|
||||
@ -74,7 +73,7 @@ static void *SparseArrayFind(SparseArray * sarray, uint32_t * index)
|
||||
uint32_t max = MAX_INDEX(sarray);
|
||||
if (sarray->shift == 0)
|
||||
{
|
||||
while (j<max)
|
||||
while (j<=max)
|
||||
{
|
||||
if (sarray->data[j] != SARRAY_EMPTY)
|
||||
{
|
||||
@ -97,13 +96,18 @@ static void *SparseArrayFind(SparseArray * sarray, uint32_t * index)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
// The recursive call will set index to the correct value for
|
||||
// the next index, but won't update j
|
||||
}
|
||||
else
|
||||
{
|
||||
//Add 2^n to index so j is still correct
|
||||
(*index) += 1<<sarray->shift;
|
||||
//Zero off the next component of the index so we don't miss any.
|
||||
*index &= zeromask;
|
||||
}
|
||||
//Go to the next child
|
||||
j++;
|
||||
//Add 2^n to index so j is still correct
|
||||
(*index) += 1<<sarray->shift;
|
||||
//Zero off the next component of the index so we don't miss any.
|
||||
*index &= zeromask;
|
||||
}
|
||||
}
|
||||
return SARRAY_EMPTY;
|
||||
@ -117,12 +121,10 @@ void *SparseArrayNext(SparseArray * sarray, uint32_t * idx)
|
||||
|
||||
void SparseArrayInsert(SparseArray * sarray, uint32_t index, void *value)
|
||||
{
|
||||
fprintf(stderr, "Inserting in : %p\n", sarray);
|
||||
if (sarray->shift > 0)
|
||||
{
|
||||
uint32_t i = MASK_INDEX(index);
|
||||
SparseArray *child = sarray->data[i];
|
||||
fprintf(stderr, "Child: %p\n", child);
|
||||
if(&EmptyArray == child)
|
||||
{
|
||||
// Insert missing nodes
|
||||
@ -140,7 +142,6 @@ void SparseArrayInsert(SparseArray * sarray, uint32_t index, void *value)
|
||||
init_pointers(newsarray);
|
||||
sarray->data[i] = newsarray;
|
||||
child = newsarray;
|
||||
fprintf(stderr, "Created child: %p\n", child);
|
||||
}// FIXME: Concurrency (don't CoW twice)
|
||||
else if (child->refCount > 1)
|
||||
{
|
||||
@ -149,7 +150,6 @@ void SparseArrayInsert(SparseArray * sarray, uint32_t index, void *value)
|
||||
SparseArrayDestroy(child);
|
||||
child = sarray->data[i];
|
||||
}
|
||||
fprintf(stderr, "Recursing in insert\n");
|
||||
SparseArrayInsert(child, index, value);
|
||||
}
|
||||
else
|
||||
|
Loading…
Reference in New Issue
Block a user