static inline NXMapTable *pendingClassRefsMapTable(void);
static inline NXMapTable *pendingSubclassesMapTable(void);
static void pendClassInstallation(Class cls, const char *superName);
-static void pendClassReference(Class *ref, const char *className, BOOL isMeta);
+static void pendClassReference(Class *ref, const char *className, bool isMeta);
static void resolve_references_to_class(Class cls);
static void resolve_subclasses_of_class(Class cls);
static void really_connect_class(Class cls, Class supercls);
-static BOOL connect_class(Class cls);
-static void map_method_descs (struct objc_method_description_list * methods, BOOL copy);
+static bool connect_class(Class cls);
+static void map_method_descs (struct objc_method_description_list * methods, bool copy);
static void _objcTweakMethodListPointerForClass(Class cls);
static inline void _objc_add_category(Class cls, old_category *category, int version);
-static BOOL _objc_add_category_flush_caches(Class cls, old_category *category, int version);
+static bool _objc_add_category_flush_caches(Class cls, old_category *category, int version);
static _objc_unresolved_category *reverse_cat(_objc_unresolved_category *cat);
static void resolve_categories_for_class(Class cls);
-static BOOL _objc_register_category(old_category *cat, int version);
+static bool _objc_register_category(old_category *cat, int version);
// Function called when a class is loaded from an image
count = 0;
state = NXInitHashState (table);
while (NXNextHashState (table, &state, (void **) &data))
- printf ("class %d: %s\n", ++count, data->getName());
+ printf ("class %d: %s\n", ++count, data->nameForLogging());
}
// about 520 classes. Larger apps (like IB or WOB) have more like
// 800 classes. Some customers have massive quantities of classes.
// Foundation-only programs aren't likely to notice the ~6K loss.
- class_hash = NXCreateHashTableFromZone (classHashPrototype,
- 16,
- nil,
- _objc_internal_zone ());
+ class_hash = NXCreateHashTable(classHashPrototype, 16, nil);
_objc_debug_class_hash = class_hash;
}
Class cls;
int cnt, num;
- mutex_lock(&classLock);
- if (!class_hash) {
- mutex_unlock(&classLock);
- return 0;
- }
+ mutex_locker_t lock(classLock);
+ if (!class_hash) return 0;
+
num = NXCountHashTable(class_hash);
- if (nil == buffer) {
- mutex_unlock(&classLock);
- return num;
- }
+ if (nil == buffer) return num;
+
cnt = 0;
state = NXInitHashState(class_hash);
while (cnt < bufferLen &&
{
buffer[cnt++] = cls;
}
- mutex_unlock(&classLock);
+
return num;
}
Class *result;
unsigned int count;
- mutex_lock(&classLock);
+ mutex_locker_t lock(classLock);
result = nil;
count = class_hash ? NXCountHashTable(class_hash) : 0;
}
result[count] = nil;
}
- mutex_unlock(&classLock);
if (outCount) *outCount = count;
return result;
NXMapState state;
Protocol **result;
- mutex_lock(&classLock);
+ mutex_locker_t lock(classLock);
count = NXCountMapTable(protocol_map);
if (count == 0) {
- mutex_unlock(&classLock);
if (outCount) *outCount = 0;
return nil;
}
result[i++] = nil;
assert(i == count+1);
- mutex_unlock(&classLock);
-
if (outCount) *outCount = count;
return result;
}
return 0;
// Call through to real hash function
- return _objc_strhash (data->getName());
+ return _objc_strhash (data->mangledName());
}
/***********************************************************************
static int classIsEqual(void *info, Class name, Class cls)
{
// Standard string comparison
- return strcmp(name->getName(), cls->getName()) == 0;
+ return strcmp(name->mangledName(), cls->mangledName()) == 0;
}
{
if (!future_class_to_original_class_map) {
future_class_to_original_class_map =
- NXCreateMapTableFromZone (NXPtrValueMapPrototype, FUTURE_COUNT,
- _objc_internal_zone ());
+ NXCreateMapTable(NXPtrValueMapPrototype, FUTURE_COUNT);
original_class_to_future_class_map =
- NXCreateMapTableFromZone (NXPtrValueMapPrototype, FUTURE_COUNT,
- _objc_internal_zone ());
+ NXCreateMapTable(NXPtrValueMapPrototype, FUTURE_COUNT);
}
NXMapInsert (future_class_to_original_class_map,
// CF requests about 20 future classes, plus HIToolbox has one.
if (!future_class_hash) {
future_class_hash =
- NXCreateHashTableFromZone(classHashPrototype, FUTURE_COUNT,
- nil, _objc_internal_zone());
+ NXCreateHashTable(classHashPrototype, FUTURE_COUNT, nil);
}
- cls->name = _strdup_internal(name);
+ cls->name = strdup(name);
NXHashInsert(future_class_hash, cls);
if (PrintFuture) {
/***********************************************************************
-* objc_setFutureClass.
-* Like objc_getFutureClass, but uses the provided memory block.
-* If the class already exists, a posing-like substitution is performed.
-* Not thread safe.
+* objc_getFutureClass. Return the id of the named class.
+* If the class does not exist, return an uninitialized class
+* structure that will be used for the class when and if it
+* does get loaded.
+* Not thread safe.
**********************************************************************/
-void objc_setFutureClass(Class cls, const char *name)
+Class objc_getFutureClass(const char *name)
{
- Class oldcls;
- Class newcls = cls; // Not a real class!
-
- if ((oldcls = look_up_class(name, NO/*unconnected*/, NO/*classhandler*/))) {
- setOriginalClassForFutureClass(newcls, oldcls);
- // fixme hack
- memcpy(newcls, oldcls, sizeof(struct objc_class));
- newcls->info &= ~CLS_EXT;
+ Class cls;
- mutex_lock(&classLock);
- NXHashRemove(class_hash, oldcls);
- objc_removeRegisteredClass(oldcls);
- change_class_references(newcls, oldcls, nil, YES);
- NXHashInsert(class_hash, newcls);
- objc_addRegisteredClass(newcls);
- mutex_unlock(&classLock);
- } else {
- makeFutureClass(newcls, name);
+ // YES unconnected, NO class handler
+ // (unconnected is OK because it will someday be the real class)
+ cls = look_up_class(name, YES, NO);
+ if (cls) {
+ if (PrintFuture) {
+ _objc_inform("FUTURE: found %p already in use for %s",
+ (void*)cls, name);
+ }
+ return cls;
}
+
+ // No class or future class with that name yet. Make one.
+ // fixme not thread-safe with respect to
+ // simultaneous library load or getFutureClass.
+ return _objc_allocateFutureClass(name);
}
BOOL _class_isFutureClass(Class cls)
{
- return cls && future_class_hash && NXHashGet(future_class_hash, cls);
+ return cls && cls->isFuture();
+}
+
+bool objc_class::isFuture()
+{
+ return future_class_hash && NXHashGet(future_class_hash, this);
}
**********************************************************************/
Protocol *objc_getProtocol(const char *name)
{
- Protocol *result;
+ mutex_locker_t lock(classLock);
if (!protocol_map) return nil;
- mutex_lock(&classLock);
- result = (Protocol *)NXMapGet(protocol_map, name);
- mutex_unlock(&classLock);
- return result;
+ return (Protocol *)NXMapGet(protocol_map, name);
}
* 3. classLoader callback
* 4. classHandler callback (optional)
**********************************************************************/
-Class look_up_class(const char *aClassName, BOOL includeUnconnected, BOOL includeClassHandler)
+Class look_up_class(const char *aClassName, bool includeUnconnected,
+ bool includeClassHandler)
{
- BOOL includeClassLoader = YES; // class loader cannot be skipped
+ bool includeClassLoader = YES; // class loader cannot be skipped
Class result = nil;
struct objc_class query;
if (!result && class_hash) {
// Check ordinary classes
- mutex_lock (&classLock);
+ mutex_locker_t lock(classLock);
result = (Class)NXHashGet(class_hash, &query);
- mutex_unlock (&classLock);
}
if (!result && includeUnconnected && unconnected_class_hash) {
// Check not-yet-connected classes
- mutex_lock(&classLock);
+ mutex_locker_t lock(classLock);
result = (Class)NXHashGet(unconnected_class_hash, &query);
- mutex_unlock(&classLock);
}
if (!result && includeClassLoader && _objc_classLoader) {
**********************************************************************/
bool objc_class::isConnected()
{
- bool result;
- mutex_lock(&classLock);
- result = NXHashMember(class_hash, this);
- mutex_unlock(&classLock);
- return result;
+ mutex_locker_t lock(classLock);
+ return NXHashMember(class_hash, this);
}
{
// Allocate table if needed
if (!pendingClassRefsMap) {
- pendingClassRefsMap =
- NXCreateMapTableFromZone(NXStrValueMapPrototype,
- 10, _objc_internal_zone ());
+ pendingClassRefsMap = NXCreateMapTable(NXStrValueMapPrototype, 10);
}
// Return table pointer
{
// Allocate table if needed
if (!pendingSubclassesMap) {
- pendingSubclassesMap =
- NXCreateMapTableFromZone(NXStrValueMapPrototype,
- 10, _objc_internal_zone ());
+ pendingSubclassesMap = NXCreateMapTable(NXStrValueMapPrototype, 10);
}
// Return table pointer
}
// Create entry referring to this class
- pending = (PendingSubclass *)_malloc_internal(sizeof(PendingSubclass));
+ pending = (PendingSubclass *)malloc(sizeof(PendingSubclass));
pending->subclass = cls;
// Link new entry into head of list of entries for this class
* pendClassReference
* Fix up a class ref when the class with the given name becomes connected.
**********************************************************************/
-static void pendClassReference(Class *ref, const char *className, BOOL isMeta)
+static void pendClassReference(Class *ref, const char *className, bool isMeta)
{
NXMapTable *table;
PendingClassRef *pending;
table = pendingClassRefsMapTable ();
// Create entry containing the class reference
- pending = (PendingClassRef *)_malloc_internal(sizeof(PendingClassRef));
+ pending = (PendingClassRef *)malloc(sizeof(PendingClassRef));
pending->ref = ref;
if (isMeta) {
pending->ref = (Class *)((uintptr_t)pending->ref | 1);
while (pending) {
PendingClassRef *next = pending->next;
if (pending->ref) {
- BOOL isMeta = ((uintptr_t)pending->ref & 1) ? YES : NO;
+ bool isMeta = (uintptr_t)pending->ref & 1;
Class *ref =
(Class *)((uintptr_t)pending->ref & ~(uintptr_t)1);
*ref = isMeta ? cls->ISA() : cls;
}
- _free_internal(pending);
+ free(pending);
pending = next;
}
while (pending) {
PendingSubclass *next = pending->next;
if (pending->subclass) connect_class(pending->subclass);
- _free_internal(pending);
+ free(pending);
pending = next;
}
}
// Connect superclass pointers.
set_superclass(cls, supercls, YES);
- // Update GC layouts
- // For paranoia, this is a conservative update:
- // only non-strong -> strong and weak -> strong are corrected.
- if (UseGC && supercls &&
- (cls->info & CLS_EXT) && (supercls->info & CLS_EXT))
+ // Done!
+ cls->info |= CLS_CONNECTED;
+
{
- BOOL layoutChanged;
- layout_bitmap ivarBitmap =
- layout_bitmap_create(cls->ivar_layout,
- cls->instance_size,
- cls->instance_size, NO);
-
- layout_bitmap superBitmap =
- layout_bitmap_create(supercls->ivar_layout,
- supercls->instance_size,
- supercls->instance_size, NO);
-
- // non-strong -> strong: bits set in super should be set in sub
- layoutChanged = layout_bitmap_or(ivarBitmap, superBitmap, cls->name);
- layout_bitmap_free(superBitmap);
+ mutex_locker_t lock(classLock);
- if (layoutChanged) {
- layout_bitmap weakBitmap = {};
- BOOL weakLayoutChanged = NO;
-
- if (cls->ext && cls->ext->weak_ivar_layout) {
- // weak -> strong: strong bits should be cleared in weak layout
- // This is a subset of non-strong -> strong
- weakBitmap =
- layout_bitmap_create(cls->ext->weak_ivar_layout,
- cls->instance_size,
- cls->instance_size, YES);
-
- weakLayoutChanged =
- layout_bitmap_clear(weakBitmap, ivarBitmap, cls->name);
- } else {
- // no existing weak ivars, so no weak -> strong changes
- }
-
- // Rebuild layout strings.
- if (PrintIvars) {
- _objc_inform("IVARS: gc layout changed "
- "for class %s (super %s)",
- cls->name, supercls->name);
- if (weakLayoutChanged) {
- _objc_inform("IVARS: gc weak layout changed "
- "for class %s (super %s)",
- cls->name, supercls->name);
- }
- }
- cls->ivar_layout = layout_string_create(ivarBitmap);
- if (weakLayoutChanged) {
- cls->ext->weak_ivar_layout = layout_string_create(weakBitmap);
- }
-
- layout_bitmap_free(weakBitmap);
+ // Update hash tables.
+ NXHashRemove(unconnected_class_hash, cls);
+ oldCls = (Class)NXHashInsert(class_hash, cls);
+
+ // Delete unconnected_class_hash if it is now empty.
+ if (NXCountHashTable(unconnected_class_hash) == 0) {
+ NXFreeHashTable(unconnected_class_hash);
+ unconnected_class_hash = nil;
}
- layout_bitmap_free(ivarBitmap);
- }
-
- // Done!
- cls->info |= CLS_CONNECTED;
-
- mutex_lock(&classLock);
-
- // Update hash tables.
- NXHashRemove(unconnected_class_hash, cls);
- oldCls = (Class)NXHashInsert(class_hash, cls);
- objc_addRegisteredClass(cls);
-
- // Delete unconnected_class_hash if it is now empty.
- if (NXCountHashTable(unconnected_class_hash) == 0) {
- NXFreeHashTable(unconnected_class_hash);
- unconnected_class_hash = nil;
- }
-
- // No duplicate classes allowed.
- // Duplicates should have been rejected by _objc_read_classes_from_image.
- assert(!oldCls);
-
- mutex_unlock(&classLock);
+ // No duplicate classes allowed.
+ // Duplicates should have been rejected by _objc_read_classes_from_image
+ assert(!oldCls);
+ }
// Fix up pended class refs to this class, if any
resolve_references_to_class(cls);
// Connect newly-connectable subclasses
resolve_subclasses_of_class(cls);
- // GC debugging: make sure all classes with -dealloc also have -finalize
- if (DebugFinalizers) {
- extern IMP findIMPInClass(Class cls, SEL sel);
- if (findIMPInClass(cls, sel_getUid("dealloc")) &&
- ! findIMPInClass(cls, sel_getUid("finalize")))
- {
- _objc_inform("GC: class '%s' implements -dealloc but not -finalize", cls->name);
- }
- }
-
// Debugging: if this class has ivars, make sure this class's ivars don't
// overlap with its super's. This catches some broken fragile base classes.
// Do not use super->instance_size vs. self->ivar[0] to check this.
* Returns FALSE if cls could not be connected for some reason
* (missing superclass or still-unconnected superclass)
**********************************************************************/
-static BOOL connect_class(Class cls)
+static bool connect_class(Class cls)
{
if (cls->isConnected()) {
// This class is already connected to its superclass.
* installation.
* Returns YES if some method caches now need to be flushed.
**********************************************************************/
-static BOOL _objc_read_categories_from_image (header_info * hi)
+static bool _objc_read_categories_from_image (header_info * hi)
{
Module mods;
size_t midx;
- BOOL needFlush = NO;
+ bool needFlush = NO;
- if (_objcHeaderIsReplacement(hi)) {
+ if (hi->info()->isReplacement()) {
// Ignore any categories in this image
return NO;
}
-
// Major loop - process all modules in the header
mods = hi->mod_ptr;
Module mods;
int isBundle = headerIsBundle(hi);
- if (_objcHeaderIsReplacement(hi)) {
+ if (hi->info()->isReplacement()) {
// Ignore any classes in this image
return;
}
// If other Objective-C libraries are found, immediately resize
// class_hash, assuming that Foundation and AppKit are about
// to add lots of classes.
- mutex_lock(&classLock);
- if (hi->mhdr != libobjc_header && _NXHashCapacity(class_hash) < 1024) {
- _NXHashRehashToCapacity(class_hash, 1024);
+ {
+ mutex_locker_t lock(classLock);
+ if (hi->mhdr() != libobjc_header && _NXHashCapacity(class_hash) < 1024) {
+ _NXHashRehashToCapacity(class_hash, 1024);
+ }
}
- mutex_unlock(&classLock);
// Major loop - process all modules in the image
mods = hi->mod_ptr;
for (index = 0; index < mods[midx].symtab->cls_def_cnt; index += 1)
{
Class newCls, oldCls;
- BOOL rejected;
+ bool rejected;
// Locate the class description pointer
newCls = (Class)mods[midx].symtab->defs[index];
if (_class_hasLoadMethod(newCls)) {
newCls->ISA()->info |= CLS_HAS_LOAD_METHOD;
}
-
- // Install into unconnected_class_hash.
- mutex_lock(&classLock);
- if (future_class_hash) {
- Class futureCls = (Class)
- NXHashRemove(future_class_hash, newCls);
- if (futureCls) {
- // Another class structure for this class was already
- // prepared by objc_getFutureClass(). Use it instead.
- _free_internal((char *)futureCls->name);
- memcpy(futureCls, newCls, sizeof(objc_class));
- setOriginalClassForFutureClass(futureCls, newCls);
- newCls = futureCls;
-
- if (NXCountHashTable(future_class_hash) == 0) {
- NXFreeHashTable(future_class_hash);
- future_class_hash = nil;
+ // Install into unconnected_class_hash.
+ {
+ mutex_locker_t lock(classLock);
+
+ if (future_class_hash) {
+ Class futureCls = (Class)
+ NXHashRemove(future_class_hash, newCls);
+ if (futureCls) {
+ // Another class structure for this class was already
+ // prepared by objc_getFutureClass(). Use it instead.
+ free((char *)futureCls->name);
+ memcpy(futureCls, newCls, sizeof(objc_class));
+ setOriginalClassForFutureClass(futureCls, newCls);
+ newCls = futureCls;
+
+ if (NXCountHashTable(future_class_hash) == 0) {
+ NXFreeHashTable(future_class_hash);
+ future_class_hash = nil;
+ }
}
}
+
+ if (!unconnected_class_hash) {
+ unconnected_class_hash =
+ NXCreateHashTable(classHashPrototype, 128, nil);
+ }
+
+ if ((oldCls = (Class)NXHashGet(class_hash, newCls)) ||
+ (oldCls = (Class)NXHashGet(unconnected_class_hash, newCls)))
+ {
+ // Another class with this name exists. Complain and reject.
+ inform_duplicate(newCls->name, oldCls, newCls);
+ rejected = YES;
+ }
+ else {
+ NXHashInsert(unconnected_class_hash, newCls);
+ rejected = NO;
+ }
}
- if (!unconnected_class_hash) {
- unconnected_class_hash =
- NXCreateHashTableFromZone(classHashPrototype, 128,
- nil, _objc_internal_zone());
- }
-
- if ((oldCls = (Class)NXHashGet(class_hash, newCls)) ||
- (oldCls = (Class)NXHashGet(unconnected_class_hash, newCls)))
- {
- // Another class with this name exists. Complain and reject.
- inform_duplicate(newCls->name, oldCls, newCls);
- rejected = YES;
- }
- else {
- NXHashInsert(unconnected_class_hash, newCls);
- rejected = NO;
- }
-
- mutex_unlock(&classLock);
-
if (!rejected) {
// Attach pended categories for this class, if any
resolve_categories_for_class(newCls);
unsigned int index;
unsigned int midx;
Module mods;
- BOOL replacement = _objcHeaderIsReplacement(hi);
+ bool replacement = hi->info()->isReplacement();
// Major loop - process all modules in the image
mods = hi->mod_ptr;
{
Class cls = (Class)mods[midx].symtab->defs[index];
if (! replacement) {
- BOOL connected;
+ bool connected;
Class futureCls = getFutureClassForOriginalClass(cls);
if (futureCls) {
// objc_getFutureClass() requested a different class
* not yet exist, the reference is added to a list of pending references
* to be fixed up at a later date.
**********************************************************************/
-static void fix_class_ref(Class *ref, const char *name, BOOL isMeta)
+static void fix_class_ref(Class *ref, const char *name, bool isMeta)
{
Class cls;
* can still be used after the bundle's data segment is unmapped.
* Returns YES if dst was written to, NO if it was unchanged.
**********************************************************************/
-static inline void map_selrefs(SEL *sels, size_t count, BOOL copy)
+static inline void map_selrefs(SEL *sels, size_t count, bool copy)
{
size_t index;
* for registering selectors from unloadable bundles, so the selector
* can still be used after the bundle's data segment is unmapped.
**********************************************************************/
-static void map_method_descs (struct objc_method_description_list * methods, BOOL copy)
+static void map_method_descs (struct objc_method_description_list * methods, bool copy)
{
int index;
**********************************************************************/
struct objc_method_description *
lookup_protocol_method(old_protocol *proto, SEL aSel,
- BOOL isRequiredMethod, BOOL isInstanceMethod,
- BOOL recursive)
+ bool isRequiredMethod, bool isInstanceMethod,
+ bool recursive)
{
struct objc_method_description *m = nil;
old_protocol_ext *ext;
}
-objc_property_t protocol_getProperty(Protocol *p, const char *name,
- BOOL isRequiredProperty, BOOL isInstanceProperty)
+objc_property_t
+protocol_getProperty(Protocol *p, const char *name,
+ BOOL isRequiredProperty, BOOL isInstanceProperty)
{
old_protocol *proto = oldprotocol(p);
old_protocol_ext *ext;
if (!proto || !name) return nil;
- if (!isRequiredProperty || !isInstanceProperty) {
- // Only required instance properties are currently supported
+ if (!isRequiredProperty) {
+ // Only required properties are currently supported
return nil;
}
if ((ext = ext_for_protocol(proto))) {
old_property_list *plist;
- if ((plist = ext->instance_properties)) {
+ if (isInstanceProperty) plist = ext->instance_properties;
+ else if (ext->hasClassPropertiesField()) plist = ext->class_properties;
+ else plist = nil;
+
+ if (plist) {
uint32_t i;
for (i = 0; i < plist->count; i++) {
old_property *prop = property_list_nth(plist, i);
}
-objc_property_t *protocol_copyPropertyList(Protocol *p, unsigned int *outCount)
+objc_property_t *
+protocol_copyPropertyList2(Protocol *p, unsigned int *outCount,
+ BOOL isRequiredProperty, BOOL isInstanceProperty)
{
old_property **result = nil;
old_protocol_ext *ext;
old_property_list *plist;
old_protocol *proto = oldprotocol(p);
- if (! (ext = ext_for_protocol(proto))) {
+ if (! (ext = ext_for_protocol(proto)) || !isRequiredProperty) {
+ // Only required properties are currently supported.
if (outCount) *outCount = 0;
return nil;
}
- plist = ext->instance_properties;
+ if (isInstanceProperty) plist = ext->instance_properties;
+ else if (ext->hasClassPropertiesField()) plist = ext->class_properties;
+ else plist = nil;
+
result = copyPropertyList(plist, outCount);
return (objc_property_t *)result;
}
+objc_property_t *protocol_copyPropertyList(Protocol *p, unsigned int *outCount)
+{
+ return protocol_copyPropertyList2(p, outCount, YES, YES);
+}
+
/***********************************************************************
* protocol_copyProtocolList
objc_allocateProtocol(const char *name)
{
Class cls = objc_getClass("__IncompleteProtocol");
+ assert(cls);
- mutex_lock(&classLock);
+ mutex_locker_t lock(classLock);
- if (NXMapGet(protocol_map, name)) {
- mutex_unlock(&classLock);
- return nil;
- }
+ if (NXMapGet(protocol_map, name)) return nil;
old_protocol *result = (old_protocol *)
- _calloc_internal(1, sizeof(old_protocol)
+ calloc(1, sizeof(old_protocol)
+ sizeof(old_protocol_ext));
old_protocol_ext *ext = (old_protocol_ext *)(result+1);
result->isa = cls;
- result->protocol_name = _strdup_internal(name);
+ result->protocol_name = strdup(name);
ext->size = sizeof(old_protocol_ext);
// fixme reserve name without installing
NXMapInsert(protocol_ext_map, result, result+1);
- mutex_unlock(&classLock);
-
return (Protocol *)result;
}
Class oldcls = objc_getClass("__IncompleteProtocol");
Class cls = objc_getClass("Protocol");
- mutex_lock(&classLock);
+ mutex_locker_t lock(classLock);
if (proto->isa == cls) {
_objc_inform("objc_registerProtocol: protocol '%s' was already "
"registered!", proto->protocol_name);
- mutex_unlock(&classLock);
return;
}
if (proto->isa != oldcls) {
_objc_inform("objc_registerProtocol: protocol '%s' was not allocated "
"with objc_allocateProtocol!", proto->protocol_name);
- mutex_unlock(&classLock);
return;
}
proto->isa = cls;
NXMapKeyCopyingInsert(protocol_map, proto->protocol_name, proto);
-
- mutex_unlock(&classLock);
}
if (!proto_gen) return;
if (!addition_gen) return;
- mutex_lock(&classLock);
+ mutex_locker_t lock(classLock);
if (proto->isa != cls) {
_objc_inform("protocol_addProtocol: modified protocol '%s' is not "
"under construction!", proto->protocol_name);
- mutex_unlock(&classLock);
return;
}
if (addition->isa == cls) {
_objc_inform("protocol_addProtocol: added protocol '%s' is still "
"under construction!", addition->protocol_name);
- mutex_unlock(&classLock);
return;
}
size_t size = sizeof(old_protocol_list)
+ protolist->count * sizeof(protolist->list[0]);
protolist = (old_protocol_list *)
- _realloc_internal(protolist, size);
+ realloc(protolist, size);
} else {
protolist = (old_protocol_list *)
- _calloc_internal(1, sizeof(old_protocol_list));
+ calloc(1, sizeof(old_protocol_list));
}
protolist->list[protolist->count++] = addition;
proto->protocol_list = protolist;
-
- mutex_unlock(&classLock);
}
{
if (!*list) {
*list = (struct objc_method_description_list *)
- _calloc_internal(sizeof(struct objc_method_description_list), 1);
+ calloc(sizeof(struct objc_method_description_list), 1);
} else {
size_t size = sizeof(struct objc_method_description_list)
+ (*list)->count * sizeof(struct objc_method_description);
*list = (struct objc_method_description_list *)
- _realloc_internal(*list, size);
+ realloc(*list, size);
}
struct objc_method_description *desc = &(*list)->list[(*list)->count++];
desc->name = name;
- desc->types = _strdup_internal(types ?: "");
+ desc->types = strdup(types ?: "");
}
void
if (!proto_gen) return;
- mutex_lock(&classLock);
+ mutex_locker_t lock(classLock);
if (proto->isa != cls) {
_objc_inform("protocol_addMethodDescription: protocol '%s' is not "
"under construction!", proto->protocol_name);
- mutex_unlock(&classLock);
return;
}
old_protocol_ext *ext = (old_protocol_ext *)(proto+1);
_protocol_addMethod(&ext->optional_class_methods, name, types);
}
-
- mutex_unlock(&classLock);
}
{
if (!*plist) {
*plist = (old_property_list *)
- _calloc_internal(sizeof(old_property_list), 1);
+ calloc(sizeof(old_property_list), 1);
(*plist)->entsize = sizeof(old_property);
} else {
*plist = (old_property_list *)
- _realloc_internal(*plist, sizeof(old_property_list)
+ realloc(*plist, sizeof(old_property_list)
+ (*plist)->count * (*plist)->entsize);
}
old_property *prop = property_list_nth(*plist, (*plist)->count++);
- prop->name = _strdup_internal(name);
+ prop->name = strdup(name);
prop->attributes = copyPropertyAttributeString(attrs, count);
}
if (!proto) return;
if (!name) return;
- mutex_lock(&classLock);
+ mutex_locker_t lock(classLock);
if (proto->isa != cls) {
_objc_inform("protocol_addProperty: protocol '%s' is not "
"under construction!", proto->protocol_name);
- mutex_unlock(&classLock);
return;
}
if (isRequiredProperty && isInstanceProperty) {
_protocol_addProperty(&ext->instance_properties, name, attrs, count);
}
- //else if (isRequiredProperty && !isInstanceProperty) {
- // _protocol_addProperty(&ext->class_properties, name, attrs, count);
- //} else if (!isRequiredProperty && isInstanceProperty) {
+ else if (isRequiredProperty && !isInstanceProperty) {
+ _protocol_addProperty(&ext->class_properties, name, attrs, count);
+ }
+ // else if (!isRequiredProperty && isInstanceProperty) {
// _protocol_addProperty(&ext->optional_instance_properties, name, attrs, count);
- //} else /* !isRequiredProperty && !isInstanceProperty) */ {
+ //}
+ // else /* !isRequiredProperty && !isInstanceProperty) */ {
// _protocol_addProperty(&ext->optional_class_properties, name, attrs, count);
//}
-
- mutex_unlock(&classLock);
}
* specified image, selectorize the method names and add to the protocol hash.
**********************************************************************/
-static BOOL versionIsExt(uintptr_t version, const char *names, size_t size)
+static bool versionIsExt(uintptr_t version, const char *names, size_t size)
{
// CodeWarrior used isa field for string "Protocol"
// from section __OBJC,__class_names. rdar://4951638
// the only version number used on Mac OS X was 2.
// gcc (10.5 and later) uses isa field for ext pointer
- if (version < PAGE_SIZE) {
+ if (version < 4096 /* not PAGE_SIZE */) {
return NO;
}
}
static void fix_protocol(old_protocol *proto, Class protocolClass,
- BOOL isBundle, const char *names, size_t names_size)
+ bool isBundle, const char *names, size_t names_size)
{
uintptr_t version;
if (!proto) return;
const char *names;
size_t names_size;
- mutex_lock(&classLock);
+ mutex_locker_t lock(classLock);
// Allocate the protocol registry if necessary.
if (!protocol_map) {
protocol_map =
- NXCreateMapTableFromZone(NXStrValueMapPrototype, 32,
- _objc_internal_zone());
+ NXCreateMapTable(NXStrValueMapPrototype, 32);
}
if (!protocol_ext_map) {
protocol_ext_map =
- NXCreateMapTableFromZone(NXPtrValueMapPrototype, 32,
- _objc_internal_zone());
+ NXCreateMapTable(NXPtrValueMapPrototype, 32);
}
protos = _getObjcProtocols(hi, &count);
for (i = 0; i < count; i++) {
fix_protocol(protos[i], protocolClass, isBundle, names, names_size);
}
-
- mutex_unlock(&classLock);
}
size_t count;
SEL *sels;
+ bool preoptimized = hi->isPreoptimized();
+
if (PrintPreopt) {
- if (sel_preoptimizationValid(hi)) {
+ if (preoptimized) {
_objc_inform("PREOPTIMIZATION: honoring preoptimized selectors in %s",
- hi->fname);
+ hi->fname());
}
- else if (_objcHeaderOptimizedByDyld(hi)) {
+ else if (hi->info()->optimizedByDyld()) {
_objc_inform("PREOPTIMIZATION: IGNORING preoptimized selectors in %s",
- hi->fname);
+ hi->fname());
}
}
- if (sel_preoptimizationValid(hi)) return;
+ if (preoptimized) return;
sels = _getObjcSelectorRefs (hi, &count);
map_selrefs(sels, count, headerIsBundle(hi));
}
-static inline BOOL _is_threaded() {
+static inline bool _is_threaded() {
#if TARGET_OS_WIN32
return YES;
#else
* dyld_priv.h says even for 64-bit.
**********************************************************************/
void
-unmap_image(const struct mach_header *mh, intptr_t vmaddr_slide)
+unmap_image(const char *path __unused, const struct mach_header *mh)
{
- recursive_mutex_lock(&loadMethodLock);
+ recursive_mutex_locker_t lock(loadMethodLock);
unmap_image_nolock(mh);
- recursive_mutex_unlock(&loadMethodLock);
}
* Process the given images which are being mapped in by dyld.
* Calls ABI-agnostic code after taking ABI-specific locks.
**********************************************************************/
-const char *
-map_images(enum dyld_image_states state, uint32_t infoCount,
- const struct dyld_image_info infoList[])
+void
+map_images(unsigned count, const char * const paths[],
+ const struct mach_header * const mhdrs[])
{
- const char *err;
-
- recursive_mutex_lock(&loadMethodLock);
- err = map_images_nolock(state, infoCount, infoList);
- recursive_mutex_unlock(&loadMethodLock);
-
- return err;
+ recursive_mutex_locker_t lock(loadMethodLock);
+ map_images_nolock(count, paths, mhdrs);
}
/***********************************************************************
* load_images
* Process +load in the given images which are being mapped in by dyld.
-* Calls ABI-agnostic code after taking ABI-specific locks.
*
* Locking: acquires classLock and loadMethodLock
**********************************************************************/
-const char *
-load_images(enum dyld_image_states state, uint32_t infoCount,
- const struct dyld_image_info infoList[])
-{
- BOOL found;
+extern void prepare_load_methods(const headerType *mhdr);
- recursive_mutex_lock(&loadMethodLock);
+void
+load_images(const char *path __unused, const struct mach_header *mh)
+{
+ recursive_mutex_locker_t lock(loadMethodLock);
// Discover +load methods
- found = load_images_nolock(state, infoCount, infoList);
+ prepare_load_methods((const headerType *)mh);
// Call +load methods (without classLock - re-entrant)
- if (found) {
- call_load_methods();
- }
-
- recursive_mutex_unlock(&loadMethodLock);
-
- return nil;
+ call_load_methods();
}
#endif
* _read_images
* Perform metadata processing for hCount images starting with firstNewHeader
**********************************************************************/
-void _read_images(header_info **hList, uint32_t hCount)
+void _read_images(header_info **hList, uint32_t hCount, int totalClasses, int unoptimizedTotalClass)
{
uint32_t i;
- BOOL categoriesLoaded = NO;
+ bool categoriesLoaded = NO;
if (!class_hash) _objc_init_class_hash();
// But not if any other threads are running - they might
// call a category method before the fixups below are complete.
if (!_is_threaded()) {
- BOOL needFlush = NO;
+ bool needFlush = NO;
for (i = 0; i < hCount; i++) {
needFlush |= _objc_read_categories_from_image(hList[i]);
}
// But not if this is the only thread - it's more
// efficient to attach categories earlier if safe.
if (!categoriesLoaded) {
- BOOL needFlush = NO;
+ bool needFlush = NO;
for (i = 0; i < hCount; i++) {
needFlush |= _objc_read_categories_from_image(hList[i]);
}
cls->info |= CLS_LOADED;
}
-void prepare_load_methods(header_info *hi)
+void prepare_load_methods(const headerType *mhdr)
{
Module mods;
unsigned int midx;
-
- if (_objcHeaderIsReplacement(hi)) {
+ header_info *hi;
+ for (hi = FirstHeader; hi; hi = hi->getNext()) {
+ if (mhdr == hi->mhdr()) break;
+ }
+ if (!hi) return;
+
+ if (hi->info()->isReplacement()) {
// Ignore any classes in this image
return;
}
// Process each class ref
for (i = 0; i < count; i++) {
if ((uintptr_t)(refs[i]) >= start && (uintptr_t)(refs[i]) < end) {
- pendClassReference(&refs[i], refs[i]->name,
- (refs[i]->info & CLS_META) ? YES : NO);
+ pendClassReference(&refs[i], refs[i]->name,
+ refs[i]->info & CLS_META);
refs[i] = nil;
}
}
unsigned int midx;
Module mods;
- mutex_lock(&classLock);
+ mutex_locker_t lock(classLock);
// Major loop - process all modules in the image
mods = hi->mod_ptr;
// Remove from class_hash
NXHashRemove(class_hash, cls);
- objc_removeRegisteredClass(cls);
// Free heap memory pointed to by the class
unload_class(cls->ISA());
// Get the location of the dying image's __OBJC segment
uintptr_t seg;
unsigned long seg_size;
- seg = (uintptr_t)getsegmentdata(hi->mhdr, "__OBJC", &seg_size);
+ seg = (uintptr_t)getsegmentdata(hi->mhdr(), "__OBJC", &seg_size);
header_info *other_hi;
- for (other_hi = FirstHeader; other_hi != nil; other_hi = other_hi->next) {
+ for (other_hi = FirstHeader; other_hi != nil; other_hi = other_hi->getNext()) {
Class *other_refs;
size_t count;
if (other_hi == hi) continue; // skip the image being unloaded
other_refs = _getObjcClassRefs(other_hi, &count);
rependClassReferences(other_refs, count, seg, seg+seg_size);
}
-
- mutex_unlock(&classLock);
}
// Get the location of the dying image's __OBJC segment
uintptr_t seg;
unsigned long seg_size;
- seg = (uintptr_t)getsegmentdata(hi->mhdr, "__OBJC", &seg_size);
+ seg = (uintptr_t)getsegmentdata(hi->mhdr(), "__OBJC", &seg_size);
_objc_inform("UNLOAD DEBUG: unloading image '%s' [%p..%p]",
- hi->fname, (void *)seg, (void*)(seg+seg_size));
+ hi->fname(), (void *)seg, (void*)(seg+seg_size));
- mutex_lock(&classLock);
+ mutex_locker_t lock(classLock);
// Make sure the image contains no categories on surviving classes.
{
}
}
}
-
- mutex_unlock(&classLock);
}
**********************************************************************/
void _unload_image(header_info *hi)
{
- recursive_mutex_assert_locked(&loadMethodLock);
+ loadMethodLock.assertLocked();
// Cleanup:
// Remove image's classes from the class list and free auxiliary data.
_objc_remove_classes_in_image(hi);
_objc_remove_categories_in_image(hi);
_objc_remove_pending_class_refs_in_image(hi);
-
+ if (hi->proto_refs) try_free(hi->proto_refs);
+
// Perform various debugging checks if requested.
if (DebugUnload) unload_paranoia(hi);
}
OBJC_WARN_DEPRECATED;
// Synchronize access to hash table
- mutex_lock (&classLock);
+ mutex_locker_t lock(classLock);
// Make sure both the class and the metaclass have caches!
// Clear all bits of the info fields except CLS_CLASS and CLS_META.
// Add the class to the table
(void) NXHashInsert (class_hash, cls);
- objc_addRegisteredClass(cls);
// Superclass is no longer a leaf for cache flushing
if (cls->superclass && (cls->superclass->info & CLS_LEAF)) {
cls->superclass->clearInfo(CLS_LEAF);
cls->superclass->ISA()->clearInfo(CLS_LEAF);
}
-
- // Desynchronize
- mutex_unlock (&classLock);
}
/***********************************************************************
// Allocate and zero a method list array
mallocSize = sizeof(old_method_list *) * initialEntries;
- ptr = (old_method_list **) _calloc_internal(1, mallocSize);
+ ptr = (old_method_list **) calloc(1, mallocSize);
// Insert the existing list into the array
ptr[initialEntries - 1] = END_OF_METHODS_LIST;
newSize = oldSize + sizeof(old_method_list *); // only increase by 1
// Grow the method list array by one.
- // This block may be from user code; don't use _realloc_internal
*list = (old_method_list **)realloc(*list, newSize);
// Zero out addition part of new array
}
}
- // Augment properties
+ // Augment instance properties
if (version >= 7 && category->instance_properties) {
if (cls->ISA()->version >= 6) {
_class_addProperties(cls, category->instance_properties);
} else {
- _objc_inform ("unable to add properties from category %s...\n", category->category_name);
+ _objc_inform ("unable to add instance properties from category %s...\n", category->category_name);
+ _objc_inform ("class `%s' must be recompiled\n", category->class_name);
+ }
+ }
+
+ // Augment class properties
+ if (version >= 7 && category->hasClassPropertiesField() &&
+ category->class_properties)
+ {
+ if (cls->ISA()->version >= 6) {
+ _class_addProperties(cls->ISA(), category->class_properties);
+ } else {
+ _objc_inform ("unable to add class properties from category %s...\n", category->category_name);
_objc_inform ("class `%s' must be recompiled\n", category->class_name);
}
}
* methods into the class it augments, and flush the class' method cache.
* Return YES if some method caches now need to be flushed.
**********************************************************************/
-static BOOL _objc_add_category_flush_caches(Class cls, old_category *category, int version)
+static bool _objc_add_category_flush_caches(Class cls, old_category *category, int version)
{
- BOOL needFlush = NO;
+ bool needFlush = NO;
// Install the category's methods into its intended class
- mutex_lock(&methodListLock);
- _objc_add_category (cls, category, version);
- mutex_unlock(&methodListLock);
+ {
+ mutex_locker_t lock(methodListLock);
+ _objc_add_category (cls, category, version);
+ }
// Queue for cache flushing so category's methods can get called
if (category->instance_methods) {
// Delink and reclaim this registration
next = pending->next;
- _free_internal(pending);
+ free(pending);
pending = next;
}
}
* they were discovered.
* Returns YES if some method caches now need to be flushed.
**********************************************************************/
-static BOOL _objc_register_category(old_category *cat, int version)
+static bool _objc_register_category(old_category *cat, int version)
{
_objc_unresolved_category * new_cat;
_objc_unresolved_category * old;
// Create category lookup table if needed
if (!category_hash)
- category_hash = NXCreateMapTableFromZone (NXStrValueMapPrototype,
- 128,
- _objc_internal_zone ());
+ category_hash = NXCreateMapTable(NXStrValueMapPrototype, 128);
// Locate an existing list of categories, if any, for the class.
old = (_objc_unresolved_category *)
// The category list is built backwards, and is reversed again
// by resolve_categories_for_class().
new_cat = (_objc_unresolved_category *)
- _malloc_internal(sizeof(_objc_unresolved_category));
+ malloc(sizeof(_objc_unresolved_category));
new_cat->next = old;
new_cat->cat = cat;
new_cat->version = version;
/***********************************************************************
* Lock management
**********************************************************************/
-rwlock_t selLock = {};
-mutex_t classLock = MUTEX_INITIALIZER;
-mutex_t methodListLock = MUTEX_INITIALIZER;
-mutex_t cacheUpdateLock = MUTEX_INITIALIZER;
-recursive_mutex_t loadMethodLock = RECURSIVE_MUTEX_INITIALIZER;
+rwlock_t selLock;
+mutex_t classLock;
+mutex_t methodListLock;
+mutex_t cacheUpdateLock;
+recursive_mutex_t loadMethodLock;
void lock_init(void)
{
- rwlock_init(&selLock);
- recursive_mutex_init(&loadMethodLock);
}