#if !__OBJC2__
#define OLD 1
-#import "objc-private.h"
-#import "objc-rtp.h"
-#import "hashtable2.h"
-#import "maptable.h"
-
-#include <sys/param.h>
-#include <assert.h>
-
-// Lock for method list access and modification.
-// Protects methodLists fields, method arrays, and CLS_NO_METHOD_ARRAY bits.
-// Classes not yet in use do not need to take this lock.
-__private_extern__ OBJC_DECLARE_LOCK(methodListLock);
-
+#include "objc-private.h"
// Freed objects have their isa set to point to this dummy class.
// This avoids the need to check for Nil classes in the messenger.
* a pointer to the freedObjectClass, so that we can catch usages of
* the freed object.
**********************************************************************/
-__private_extern__ Class _class_getFreedObjectClass(void)
+static Class _class_getFreedObjectClass(void)
{
return (Class)&freedObjectClass;
}
if (!mlist) return NULL;
for (i = 0; i < mlist->method_count; i++) {
struct old_method *m = &mlist->method_list[i];
+ if (m->method_name == (SEL)kRTAddress_ignoredSelector) continue;
if (*((const char *)m->method_name) == *meth_name && 0 == strcmp((const char *)(m->method_name), meth_name)) {
return m;
}
}
+/***********************************************************************
+* Method list fixup markers.
+* mlist->obsolete == fixed_up_method_list marks method lists with real SELs
+* versus method lists with un-uniqued char*.
+* PREOPTIMIZED VERSION:
+* Fixed-up method lists get mlist->obsolete == OBJC_FIXED_UP
+* dyld shared cache sets this for method lists it preoptimizes.
+* UN-PREOPTIMIZED VERSION
+* Fixed-up method lists get mlist->obsolete == OBJC_FIXED_UP_outside_dyld
+* dyld shared cache uses OBJC_FIXED_UP, but those aren't trusted.
+**********************************************************************/
+#define OBJC_FIXED_UP ((void *)1771)
+#define OBJC_FIXED_UP_outside_dyld ((void *)1773)
+static void *fixed_up_method_list = OBJC_FIXED_UP;
+
+// sel_init() decided that selectors in the dyld shared cache are untrustworthy
+__private_extern__ void disableSelectorPreoptimization(void)
+{
+ fixed_up_method_list = OBJC_FIXED_UP_outside_dyld;
+}
+
/***********************************************************************
* fixupSelectorsInMethodList
* Uniques selectors in the given method list.
struct old_method_list *old_mlist;
if ( ! mlist ) return NULL;
- if ( mlist->obsolete != _OBJC_FIXED_UP ) {
+ if ( mlist->obsolete == fixed_up_method_list ) {
+ // method list OK
+ } else {
BOOL isBundle = (cls->info & CLS_FROM_BUNDLE) ? YES : NO;
if (!isBundle) {
old_mlist = mlist;
method->method_name =
sel_registerNameNoLock((const char *)method->method_name, isBundle); // Always copy selector data from bundles.
+#ifndef NO_GC
if (method->method_name == (SEL)kRTAddress_ignoredSelector) {
method->method_imp = (IMP)&_objc_ignored_method;
}
+#endif
}
sel_unlock();
- mlist->obsolete = _OBJC_FIXED_UP;
+ mlist->obsolete = fixed_up_method_list;
}
return mlist;
}
*
* void *iterator = NULL;
* struct old_method_list *mlist;
-* OBJC_LOCK(&methodListLock);
+* mutex_lock(&methodListLock);
* while ((mlist = nextMethodList(cls, &iterator))) {
* // do something with mlist
* }
-* OBJC_UNLOCK(&methodListLock);
+* mutex_unlock(&methodListLock);
**********************************************************************/
static struct old_method_list *nextMethodList(struct old_class *cls,
void **it)
// OR the address of the method list pointer to fix up and return.
if (resultp) {
- if (*resultp && (*resultp)->obsolete != _OBJC_FIXED_UP) {
+ if (*resultp) {
*resultp = fixupSelectorsInMethodList(cls, *resultp);
}
*it = (void *)(index + 1);
// One method list.
struct old_method_list **mlistp;
mlistp = (struct old_method_list **)&cls->methodLists;
- if ((*mlistp)->obsolete != _OBJC_FIXED_UP) {
- *mlistp = fixupSelectorsInMethodList(cls, *mlistp);
- }
+ *mlistp = fixupSelectorsInMethodList(cls, *mlistp);
return _findMethodInList(*mlistp, sel);
}
else {
mlistp++)
{
struct old_method *m;
- if ((*mlistp)->obsolete != _OBJC_FIXED_UP) {
- *mlistp = fixupSelectorsInMethodList(cls, *mlistp);
- }
+ *mlistp = fixupSelectorsInMethodList(cls, *mlistp);
m = _findMethodInList(*mlistp, sel);
if (m) return m;
}
}
+/***********************************************************************
+* _freedHandler.
+**********************************************************************/
+static void _freedHandler(id obj, SEL sel)
+{
+ __objc_error (obj, "message %s sent to freed object=%p",
+ sel_getName(sel), obj);
+}
+
+/***********************************************************************
+* _nonexistentHandler.
+**********************************************************************/
+static void _nonexistentHandler(id obj, SEL sel)
+{
+ __objc_error (obj, "message %s sent to non-existent object=%p",
+ sel_getName(sel), obj);
+}
+
+
+/***********************************************************************
+* ABI-specific lookUpMethod helpers.
+**********************************************************************/
+__private_extern__ void lockForMethodLookup(void)
+{
+ mutex_lock(&methodListLock);
+}
+__private_extern__ void unlockForMethodLookup(void)
+{
+ mutex_unlock(&methodListLock);
+}
+__private_extern__ IMP prepareForMethodLookup(Class cls, SEL sel, BOOL init)
+{
+ mutex_assert_unlocked(&methodListLock);
+
+ // Check for freed class
+ if (cls == _class_getFreedObjectClass())
+ return (IMP) _freedHandler;
+
+ // Check for nonexistent class
+ if (cls == _class_getNonexistentObjectClass())
+ return (IMP) _nonexistentHandler;
+
+ if (init && !_class_isInitialized(cls)) {
+ _class_initialize (cls);
+ // If sel == initialize, _class_initialize will send +initialize and
+ // then the messenger will send +initialize again after this
+ // procedure finishes. Of course, if this is not being called
+ // from the messenger then it won't happen. 2778172
+ }
+
+ return NULL;
+}
+
/***********************************************************************
* class_getVariable. Return the named instance variable.
{
struct objc_property_list *result = NULL;
- OBJC_CHECK_LOCKED(&classLock);
+ mutex_assert_locked(&classLock);
if (! ((cls->info & CLS_EXT) && cls->ext)) {
// No class ext
result = NULL;
struct old_class *cls = _class_asOld(cls_gen);
if (!cls) return;
- OBJC_LOCK(&classLock);
+ mutex_lock(&classLock);
allocateExt(cls);
// fixme leak
cls->ext->weak_ivar_layout = layout ? _strdup_internal(layout) : NULL;
- OBJC_UNLOCK(&classLock);
+ mutex_unlock(&classLock);
}
if (strncmp(_class_getName(cls), "_%", 2) == 0) {
// Posee's meta's name is smashed and isn't in the class_hash,
// so objc_getClass doesn't work.
- char *baseName = strchr(_class_getName(cls), '%'); // get posee's real name
- cls = objc_getClass(baseName);
+ const char *baseName = strchr(_class_getName(cls), '%'); // get posee's real name
+ cls = (Class)objc_getClass(baseName);
} else {
- cls = objc_getClass(_class_getName(cls));
+ cls = (Class)objc_getClass(_class_getName(cls));
}
assert(cls);
}
__private_extern__ Class _category_getClass(Category cat)
{
- return objc_getClass(_category_asOld(cat)->class_name);
+ return (Class)objc_getClass(_category_asOld(cat)->class_name);
}
__private_extern__ IMP _category_getLoadMethod(Category cat)
OBJC_WARN_DEPRECATED;
- OBJC_LOCK(&methodListLock);
+ mutex_lock(&methodListLock);
result = nextMethodList(_class_asOld(cls), it);
- OBJC_UNLOCK(&methodListLock);
+ mutex_unlock(&methodListLock);
return (struct objc_method_list *)result;
}
OBJC_WARN_DEPRECATED;
// Add the methods.
- OBJC_LOCK(&methodListLock);
+ mutex_lock(&methodListLock);
_objc_insertMethods(_class_asOld(cls), (struct old_method_list *)meths, NULL);
- OBJC_UNLOCK(&methodListLock);
+ mutex_unlock(&methodListLock);
// Must flush when dynamically adding methods. No need to flush
// all the class method caches. If cls is a meta class, though,
OBJC_WARN_DEPRECATED;
// Remove the methods
- OBJC_LOCK(&methodListLock);
+ mutex_lock(&methodListLock);
_objc_removeMethods(_class_asOld(cls), (struct old_method_list *)meths);
- OBJC_UNLOCK(&methodListLock);
+ mutex_unlock(&methodListLock);
// Must flush when dynamically removing methods. No need to flush
// all the class method caches. If cls is a meta class, though,
{
Method result;
- OBJC_LOCK(&methodListLock);
+ mutex_lock(&methodListLock);
result = (Method)_getMethod(_class_asOld(cls), sel);
- OBJC_UNLOCK(&methodListLock);
+ mutex_unlock(&methodListLock);
return result;
}
{
Method result;
- OBJC_LOCK(&methodListLock);
+ mutex_lock(&methodListLock);
result = (Method)_findMethodInClass(_class_asOld(cls), sel);
- OBJC_UNLOCK(&methodListLock);
+ mutex_unlock(&methodListLock);
return result;
}
+__private_extern__ Method _class_getMethodNoSuper_nolock(Class cls, SEL sel)
+{
+ mutex_assert_locked(&methodListLock);
+ return (Method)_findMethodInClass(_class_asOld(cls), sel);
+}
+
BOOL class_conformsToProtocol(Class cls_gen, Protocol *proto_gen)
{
struct old_class *cls = oldcls(cls_gen);
struct old_protocol *proto = oldprotocol(proto_gen);
+
+ if (!cls_gen) return NO;
+ if (!proto) return NO;
if (cls->isa->version >= 3) {
struct old_protocol_list *list;
// Look for class among the posers
ret = Nil;
- OBJC_LOCK(&classLock);
+ mutex_lock(&classLock);
if (posed_class_hash)
ret = (Class) NXMapGet (posed_class_hash, name);
- OBJC_UNLOCK(&classLock);
+ mutex_unlock(&classLock);
if (ret)
return ret;
// Not a poser. Do a normal lookup.
- ret = objc_getClass (name);
+ ret = (Class)objc_getClass (name);
if (!ret)
_objc_inform ("class `%s' not linked into application", name);
**********************************************************************/
static void _objc_addOrigClass (struct old_class *origClass)
{
- OBJC_LOCK(&classLock);
+ mutex_lock(&classLock);
// Create the poser's hash table on first use
if (!posed_class_hash)
if (NXMapGet (posed_class_hash, origClass->name) == 0)
NXMapInsert (posed_class_hash, origClass->name, origClass);
- OBJC_UNLOCK(&classLock);
+ mutex_unlock(&classLock);
}
// Replace the original with the imposter in all class refs
// Major loop - process all headers
- for (hInfo = _objc_headerStart(); hInfo != NULL; hInfo = hInfo->next)
+ for (hInfo = FirstHeader; hInfo != NULL; hInfo = hInfo->next)
{
struct old_class **cls_refs;
size_t refCount;
// Imposter must be an immediate subclass of the original
if (imposter->super_class != original) {
- __objc_error(imposter_gen,
+ __objc_error((id)imposter_gen,
"[%s poseAs:%s]: target not immediate superclass",
imposter->name, original->name);
}
// Can't pose when you have instance variables (how could it work?)
if (imposter->ivars) {
- __objc_error(imposter_gen,
+ __objc_error((id)imposter_gen,
"[%s poseAs:%s]: %s defines new instance variables",
imposter->name, original->name, imposter->name);
}
// Build a string to use to replace the name of the original class.
- #define imposterNamePrefix "_%"
+#if TARGET_OS_WIN32
+# define imposterNamePrefix "_%"
imposterNamePtr = _malloc_internal(strlen(original->name) + strlen(imposterNamePrefix) + 1);
strcpy(imposterNamePtr, imposterNamePrefix);
strcat(imposterNamePtr, original->name);
- #undef imposterNamePrefix
+# undef imposterNamePrefix
+#else
+ asprintf(&imposterNamePtr, "_%%%s", original->name);
+#endif
// We lock the class hashtable, so we are thread safe with respect to
// calls to objc_getClass (). However, the class names are not
// its normal life in addition to changing the behavior of
// the original. As a hack we don't bother to copy the metaclass.
// For some reason we modify the original rather than the copy.
- copy = _class_asOld((*_zoneAlloc)((Class)imposter->isa, sizeof(struct old_class), _objc_internal_zone()));
+ copy = (struct old_class *)_malloc_internal(sizeof(struct old_class));
memmove(copy, imposter, sizeof(struct old_class));
- OBJC_LOCK(&classLock);
+ mutex_lock(&classLock);
// Remove both the imposter and the original class.
NXHashRemove (class_hash, imposter);
NXHashRemove (class_hash, original);
NXHashInsert (class_hash, copy);
+ objc_addRegisteredClass((Class)copy); // imposter & original will rejoin later, just track the new guy
// Mark the imposter as such
_class_setInfo((Class)imposter, CLS_POSING);
NXHashInsert (class_hash, imposter);
NXHashInsert (class_hash, original);
- OBJC_UNLOCK(&classLock);
+ mutex_unlock(&classLock);
return imposter_gen;
}
unsigned int subclassCount;
#endif
- OBJC_LOCK(&classLock);
- OBJC_LOCK(&cacheUpdateLock);
+ mutex_lock(&classLock);
+ mutex_lock(&cacheUpdateLock);
// Leaf classes are fastest because there are no subclass caches to flush.
// fixme instrument
_cache_flush ((Class)target);
if (!flush_meta) {
- OBJC_UNLOCK(&cacheUpdateLock);
- OBJC_UNLOCK(&classLock);
+ mutex_unlock(&cacheUpdateLock);
+ mutex_unlock(&classLock);
return; // done
} else if (target->isa && (target->isa->info & CLS_LEAF)) {
_cache_flush ((Class)target->isa);
- OBJC_UNLOCK(&cacheUpdateLock);
- OBJC_UNLOCK(&classLock);
+ mutex_unlock(&cacheUpdateLock);
+ mutex_unlock(&classLock);
return; // done
} else {
// Reset target and handle it by one of the methods below.
MaxIdealFlushCachesCount = subclassCount;
#endif
- OBJC_UNLOCK(&cacheUpdateLock);
- OBJC_UNLOCK(&classLock);
+ mutex_unlock(&cacheUpdateLock);
+ mutex_unlock(&classLock);
return;
}
MaxIdealFlushCachesCount = subclassCount;
#endif
- OBJC_UNLOCK(&cacheUpdateLock);
- OBJC_UNLOCK(&classLock);
+ mutex_unlock(&cacheUpdateLock);
+ mutex_unlock(&classLock);
}
struct old_class *supercls;
NXHashState state;
- OBJC_LOCK(&classLock);
- OBJC_LOCK(&cacheUpdateLock);
+ mutex_lock(&classLock);
+ mutex_lock(&cacheUpdateLock);
state = NXInitHashState(class_hash);
while (NXNextHashState(class_hash, &state, (void**)&cls)) {
}
}
- OBJC_UNLOCK(&cacheUpdateLock);
- OBJC_UNLOCK(&classLock);
+ mutex_unlock(&cacheUpdateLock);
+ mutex_unlock(&classLock);
}
_class_setInfo(cls, CLS_FINALIZE_ON_MAIN_THREAD);
}
+__private_extern__ BOOL _class_instancesHaveAssociatedObjects(Class cls) {
+ return _class_getInfo(cls, CLS_INSTANCES_HAVE_ASSOCIATED_OBJECTS);
+}
+
+__private_extern__ void _class_assertInstancesHaveAssociatedObjects(Class cls) {
+ _class_setInfo(cls, CLS_INSTANCES_HAVE_ASSOCIATED_OBJECTS);
+}
__private_extern__ struct old_ivar *_ivar_asOld(Ivar ivar)
{
return _method_asOld(m)->method_types;
}
-IMP method_setImplementation(Method m, IMP imp)
+static OSSpinLock impLock = OS_SPINLOCK_INIT;
+
+IMP method_setImplementation(Method m_gen, IMP imp)
{
- IMP old = _method_asOld(m)->method_imp;
- _method_asOld(m)->method_imp = imp;
+ IMP old;
+ struct old_method *m = _method_asOld(m_gen);
+ if (!m) return NULL;
+ if (!imp) return NULL;
+
+ if (m->method_name == (SEL)kIgnore) {
+ // Ignored methods stay ignored
+ return m->method_imp;
+ }
+
+ OSSpinLockLock(&impLock);
+ old = m->method_imp;
+ m->method_imp = imp;
+ OSSpinLockUnlock(&impLock);
return old;
}
+void method_exchangeImplementations(Method m1_gen, Method m2_gen)
+{
+ IMP m1_imp;
+ struct old_method *m1 = _method_asOld(m1_gen);
+ struct old_method *m2 = _method_asOld(m2_gen);
+ if (!m1 || !m2) return;
+
+ if (m1->method_name == (SEL)kIgnore || m2->method_name == (SEL)kIgnore) {
+ // Ignored methods stay ignored. Now they're both ignored.
+ m1->method_imp = (IMP)&_objc_ignored_method;
+ m2->method_imp = (IMP)&_objc_ignored_method;
+ return;
+ }
+
+ OSSpinLockLock(&impLock);
+ m1_imp = m1->method_imp;
+ m1->method_imp = m2->method_imp;
+ m2->method_imp = m1_imp;
+ OSSpinLockUnlock(&impLock);
+}
+
+
struct objc_method_description * method_getDescription(Method m)
{
if (!m) return NULL;
const char *types, BOOL replace)
{
struct old_class *cls = oldcls(cls_gen);
+ struct old_method *m;
IMP result = NULL;
if (!types) types = "";
- OBJC_LOCK(&methodListLock);
+ mutex_lock(&methodListLock);
- struct old_method *m;
if ((m = _findMethodInClass(cls, name))) {
// already exists
// fixme atomic
// fixme could be faster
struct old_method_list *mlist =
_calloc_internal(sizeof(struct old_method_list), 1);
- mlist->obsolete = _OBJC_FIXED_UP;
+ mlist->obsolete = fixed_up_method_list;
mlist->method_count = 1;
mlist->method_list[0].method_name = name;
- mlist->method_list[0].method_imp = imp;
mlist->method_list[0].method_types = _strdup_internal(types);
+ if (name != (SEL)kIgnore) {
+ mlist->method_list[0].method_imp = imp;
+ } else {
+ mlist->method_list[0].method_imp = (IMP)&_objc_ignored_method;
+ }
_objc_insertMethods(cls, mlist, NULL);
if (!(cls->info & CLS_CONSTRUCTING)) {
result = NULL;
}
- OBJC_UNLOCK(&methodListLock);
+ mutex_unlock(&methodListLock);
return result;
}
**********************************************************************/
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
{
+ IMP old;
if (!cls) return NO;
- IMP old = _class_addMethod(cls, name, imp, types, NO);
+ old = _class_addMethod(cls, name, imp, types, NO);
return old ? NO : YES;
}
if (!type) type = "";
if (name && 0 == strcmp(name, "")) name = NULL;
- OBJC_LOCK(&classLock);
+ mutex_lock(&classLock);
// Check for existing ivar with this name
// fixme check superclasses?
// align if necessary
alignBytes = 1 << alignment;
misalign = cls->instance_size % alignBytes;
- if (misalign) cls->instance_size += alignBytes - misalign;
+ if (misalign) cls->instance_size += (long)(alignBytes - misalign);
// set ivar offset and increase instance size
ivar->ivar_offset = (int)cls->instance_size;
- cls->instance_size += size;
+ cls->instance_size += (long)size;
}
- OBJC_UNLOCK(&classLock);
+ mutex_unlock(&classLock);
return result;
}
if (!cls) return NO;
if (class_conformsToProtocol(cls_gen, protocol_gen)) return NO;
- OBJC_LOCK(&classLock);
+ mutex_lock(&classLock);
// fixme optimize - protocol list doesn't escape?
plist = _calloc_internal(sizeof(struct old_protocol_list), 1);
// fixme metaclass?
- OBJC_UNLOCK(&classLock);
+ mutex_unlock(&classLock);
return YES;
}
_class_addProperties(struct old_class *cls,
struct objc_property_list *additions)
{
- if (!(cls->info & CLS_EXT)) {
- return;
- }
+ struct objc_property_list *newlist;
+
+ if (!(cls->info & CLS_EXT)) return;
- struct objc_property_list *newlist =
+ newlist =
_memdup_internal(additions, sizeof(*newlist) - sizeof(newlist->first)
+ (additions->entsize * additions->count));
- OBJC_LOCK(&classLock);
+ mutex_lock(&classLock);
allocateExt(cls);
if (!cls->ext->propertyLists) {
}
else {
// cls has a property array - make a bigger one
+ struct objc_property_list **newarray;
int count = 0;
while (cls->ext->propertyLists[count]) count++;
- struct objc_property_list **newarray =
- _malloc_internal((count+2) * sizeof(*newarray));
+ newarray = _malloc_internal((count+2) * sizeof(*newarray));
newarray[0] = newlist;
memcpy(&newarray[1], &cls->ext->propertyLists[0],
count * sizeof(*newarray));
cls->ext->propertyLists = newarray;
}
- OBJC_UNLOCK(&classLock);
+ mutex_unlock(&classLock);
}
struct old_protocol_list *plist;
Protocol **result = NULL;
unsigned int count = 0;
- unsigned int i, p;
+ unsigned int p;
if (!cls) {
if (outCount) *outCount = 0;
return NULL;
}
- OBJC_LOCK(&classLock);
+ mutex_lock(&classLock);
for (plist = cls->protocols; plist != NULL; plist = plist->next) {
count += (int)plist->count;
plist != NULL;
plist = plist->next)
{
+ int i;
for (i = 0; i < plist->count; i++) {
result[p++] = (Protocol *)plist->list[i];
}
result[p] = NULL;
}
- OBJC_UNLOCK(&classLock);
+ mutex_unlock(&classLock);
if (outCount) *outCount = count;
return result;
struct old_class *cls = _class_asOld(cls_gen);
if (!cls || !name) return NULL;
- OBJC_LOCK(&classLock);
+ mutex_lock(&classLock);
for (result = NULL; cls && !result; cls = cls->super_class) {
uintptr_t iterator = 0;
}
done:
- OBJC_UNLOCK(&classLock);
+ mutex_unlock(&classLock);
return result;
}
return NULL;
}
- OBJC_LOCK(&classLock);
+ mutex_lock(&classLock);
iterator = 0;
while ((plist = nextPropertyList(cls, &iterator))) {
result[p] = NULL;
}
- OBJC_UNLOCK(&classLock);
+ mutex_unlock(&classLock);
if (outCount) *outCount = count;
return result;
void *iterator = NULL;
Method *result = NULL;
unsigned int count = 0;
- unsigned int m, i;
+ unsigned int m;
if (!cls) {
if (outCount) *outCount = 0;
return NULL;
}
- OBJC_LOCK(&methodListLock);
+ mutex_lock(&methodListLock);
iterator = NULL;
while ((mlist = nextMethodList(cls, &iterator))) {
m = 0;
iterator = NULL;
while ((mlist = nextMethodList(cls, &iterator))) {
+ int i;
for (i = 0; i < mlist->method_count; i++) {
- result[m++] = (Method)&mlist->method_list[i];
+ Method aMethod = (Method)&mlist->method_list[i];
+ if (method_getName(aMethod) == (SEL)kIgnore) {
+ count--;
+ continue;
+ }
+ result[m++] = aMethod;
}
}
result[m] = NULL;
}
- OBJC_UNLOCK(&methodListLock);
+ mutex_unlock(&methodListLock);
if (outCount) *outCount = count;
return result;
struct old_class *cls = oldcls(cls_gen);
Ivar *result = NULL;
unsigned int count = 0;
- unsigned int i;
+ int i;
if (!cls) {
if (outCount) *outCount = 0;
}
}
-Class objc_allocateClassPair(Class superclass_gen, const char *name,
- size_t extraBytes)
+void objc_initializeClassPair(Class superclass_gen, const char *name, Class cls_gen, Class meta_gen)
{
- struct old_class *superclass = oldcls(superclass_gen);
- struct old_class *cls, *meta;
-
- if (objc_getClass(name)) return NO;
- // fixme reserve class name against simultaneous allocation
-
- if (superclass && (superclass->info & CLS_CONSTRUCTING)) {
- // Can't make subclass of an in-construction class
- return NO;
- }
-
- // Allocate new classes.
- if (superclass) {
- cls = _calloc_internal(superclass->isa->instance_size + extraBytes, 1);
- meta = _calloc_internal(superclass->isa->isa->instance_size + extraBytes, 1);
- } else {
- cls = _calloc_internal(sizeof(struct old_class) + extraBytes, 1);
- meta = _calloc_internal(sizeof(struct old_class) + extraBytes, 1);
- }
-
+ struct old_class *supercls = oldcls(superclass_gen);
+ struct old_class *cls = oldcls(cls_gen);
+ struct old_class *meta = oldcls(meta_gen);
+
// Connect to superclasses and metaclasses
cls->isa = meta;
- set_superclass(cls, superclass);
+ set_superclass(cls, supercls);
// Set basic info
cls->name = _strdup_internal(name);
meta->info = CLS_META | CLS_CONSTRUCTING | CLS_EXT | CLS_LEAF;
// Set instance size based on superclass.
- if (superclass) {
- cls->instance_size = superclass->instance_size;
- meta->instance_size = superclass->isa->instance_size;
+ if (supercls) {
+ cls->instance_size = supercls->instance_size;
+ meta->instance_size = supercls->isa->instance_size;
} else {
cls->instance_size = sizeof(struct old_class *); // just an isa
meta->instance_size = sizeof(struct old_class);
meta->cache = (Cache)&_objc_empty_cache;
meta->protocols = NULL;
cls->ext = NULL;
+}
+
+Class objc_allocateClassPair(Class superclass_gen, const char *name,
+ size_t extraBytes)
+{
+ struct old_class *supercls = oldcls(superclass_gen);
+ Class cls, meta;
+
+ if (objc_getClass(name)) return NO;
+ // fixme reserve class name against simultaneous allocation
+
+ if (supercls && (supercls->info & CLS_CONSTRUCTING)) {
+ // Can't make subclass of an in-construction class
+ return NO;
+ }
+
+ // Allocate new classes.
+ if (supercls) {
+ cls = _calloc_class(supercls->isa->instance_size + extraBytes);
+ meta = _calloc_class(supercls->isa->isa->instance_size + extraBytes);
+ } else {
+ cls = _calloc_class(sizeof(struct old_class) + extraBytes);
+ meta = _calloc_class(sizeof(struct old_class) + extraBytes);
+ }
+
+ objc_initializeClassPair(superclass_gen, name, cls, meta);
+
return (Class)cls;
}
return;
}
- OBJC_LOCK(&classLock);
+ mutex_lock(&classLock);
// Build ivar layouts
if (UseGC) {
cls->isa->info |= CLS_CONSTRUCTED;
NXHashInsertIfAbsent(class_hash, cls);
+ objc_addRegisteredClass((Class)cls);
+ //objc_addRegisteredClass(cls->isa); if we ever allocate classes from GC
- OBJC_UNLOCK(&classLock);
+ mutex_unlock(&classLock);
}
// instance_size has historically contained two extra words,
// and instance_size is what objc_getIndexedIvars() actually uses.
struct old_class *duplicate = (struct old_class *)
- calloc(original->isa->instance_size + extraBytes, 1);
+ _calloc_class(original->isa->instance_size + extraBytes);
duplicate->isa = original->isa;
duplicate->super_class = original->super_class;
duplicateMethods = (struct old_method_list *)
calloc(sizeof(struct old_method_list) +
(count-1)*sizeof(struct old_method), 1);
- duplicateMethods->obsolete = _OBJC_FIXED_UP;
+ duplicateMethods->obsolete = fixed_up_method_list;
duplicateMethods->method_count = count;
for (i = 0; i < count; i++) {
duplicateMethods->method_list[i] = *(originalMethods[i]);
free(originalMethods);
}
- OBJC_LOCK(&classLock);
+ mutex_lock(&classLock);
NXHashInsert(class_hash, duplicate);
- OBJC_UNLOCK(&classLock);
+ objc_addRegisteredClass((Class)duplicate);
+ mutex_unlock(&classLock);
return (Class)duplicate;
}
return;
}
+ mutex_lock(&classLock);
NXHashRemove(class_hash, cls);
+ objc_removeRegisteredClass((Class)cls);
unload_class(cls->isa);
unload_class(cls);
+ mutex_unlock(&classLock);
}
obj = (*_zoneAlloc)(oldObj->isa, extraBytes, zone);
size = _class_getInstanceSize(oldObj->isa) + extraBytes;
+
// fixme need C++ copy constructor
- bcopy((const char*)oldObj, (char*)obj, size);
+ objc_memmove_collectable(obj, oldObj, size);
+
+#if !defined(NO_GC)
+ if (UseGC) gc_fixup_weakreferences(obj, oldObj);
+#endif
+
return obj;
}
id (*_zoneAlloc)(Class, size_t, void *) = _internal_class_createInstanceFromZone;
id (*_zoneCopy)(id, size_t, void *) = _internal_object_copyFromZone;
id (*_zoneRealloc)(id, size_t, void *) = _internal_object_reallocFromZone;
-void (*_error)() = (void(*)())_objc_error;
+void (*_error)(id, const char *, va_list) = _objc_error;
id class_createInstance(Class cls, size_t extraBytes)