X-Git-Url: https://git.saurik.com/apple/objc4.git/blobdiff_plain/7c0e6487d7b67b6bf6c632300ee4b74e8950b051..8070259c3936ee823b758fc1ad1645ae016ba500:/runtime/objc-private.h diff --git a/runtime/objc-private.h b/runtime/objc-private.h index 3bbfc69..055fc72 100644 --- a/runtime/objc-private.h +++ b/runtime/objc-private.h @@ -25,193 +25,287 @@ * Copyright 1988-1996, NeXT Software, Inc. */ -#if !defined(_OBJC_PRIVATE_H_) +#ifndef _OBJC_PRIVATE_H_ #define _OBJC_PRIVATE_H_ -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import - -#import "objc.h" -#import "runtime.h" -#import "maptable.h" -#import "auto_zone.h" - -struct old_category; -struct old_method_list; -typedef struct { - IMP imp; - SEL sel; -} message_ref; - -#if __OBJC2__ +#include "objc-config.h" -typedef struct objc_module *Module; -typedef struct objc_cache *Cache; +/* Isolate ourselves from the definitions of id and Class in the compiler + * and public headers. + */ +#ifdef _OBJC_OBJC_H_ +#error include objc-private.h before other headers #endif +#define OBJC_TYPES_DEFINED 1 +#define OBJC_OLD_DISPATCH_PROTOTYPES 0 -#if OLD - -struct old_class { - struct old_class *isa; - struct old_class *super_class; - const char *name; - long version; - long info; - long instance_size; - struct old_ivar_list *ivars; - struct old_method_list **methodLists; - Cache cache; - struct old_protocol_list *protocols; - // CLS_EXT only - const char *ivar_layout; - struct old_class_ext *ext; -}; +#include // for nullptr_t +#include +#include -struct old_class_ext { - uint32_t size; - const char *weak_ivar_layout; - struct objc_property_list **propertyLists; -}; +struct objc_class; +struct objc_object; + +typedef struct objc_class *Class; +typedef struct objc_object *id; -struct old_category { - char *category_name; - char *class_name; - struct old_method_list *instance_methods; - struct old_method_list *class_methods; - struct old_protocol_list *protocols; - uint32_t size; - struct objc_property_list *instance_properties; +namespace { + class SideTable; }; -struct old_ivar { - char *ivar_name; - char *ivar_type; - int ivar_offset; -#ifdef __LP64__ - int space; + +union isa_t +{ + isa_t() { } + isa_t(uintptr_t value) : bits(value) { } + + Class cls; + uintptr_t bits; + +#if SUPPORT_NONPOINTER_ISA + + // extra_rc must be the MSB-most field (so it matches carry/overflow flags) + // indexed must be the LSB (fixme or get rid of it) + // shiftcls must occupy the same bits that a real class pointer would + // bits + RC_ONE is equivalent to extra_rc + 1 + // RC_HALF is the high bit of extra_rc (i.e. half of its range) + + // future expansion: + // uintptr_t fast_rr : 1; // no r/r overrides + // uintptr_t lock : 2; // lock for atomic property, @synch + // uintptr_t extraBytes : 1; // allocated with extra bytes + +# if __arm64__ +# define ISA_MASK 0x00000001fffffff8ULL +# define ISA_MAGIC_MASK 0x000003fe00000001ULL +# define ISA_MAGIC_VALUE 0x000001a400000001ULL + struct { + uintptr_t indexed : 1; + uintptr_t has_assoc : 1; + uintptr_t has_cxx_dtor : 1; + uintptr_t shiftcls : 30; // MACH_VM_MAX_ADDRESS 0x1a0000000 + uintptr_t magic : 9; + uintptr_t weakly_referenced : 1; + uintptr_t deallocating : 1; + uintptr_t has_sidetable_rc : 1; + uintptr_t extra_rc : 19; +# define RC_ONE (1ULL<<45) +# define RC_HALF (1ULL<<18) + }; + +# elif __x86_64__ +# define ISA_MASK 0x00007ffffffffff8ULL +# define ISA_MAGIC_MASK 0x0000000000000001ULL +# define ISA_MAGIC_VALUE 0x0000000000000001ULL + struct { + uintptr_t indexed : 1; + uintptr_t has_assoc : 1; + uintptr_t has_cxx_dtor : 1; + uintptr_t shiftcls : 44; // MACH_VM_MAX_ADDRESS 0x7fffffe00000 + uintptr_t weakly_referenced : 1; + uintptr_t deallocating : 1; + uintptr_t has_sidetable_rc : 1; + uintptr_t extra_rc : 14; +# define RC_ONE (1ULL<<50) +# define RC_HALF (1ULL<<13) + }; + +# else + // Available bits in isa field are architecture-specific. +# error unknown architecture +# endif + +// SUPPORT_NONPOINTER_ISA #endif + }; -struct old_ivar_list { - int ivar_count; -#ifdef __LP64__ - int space; + +struct objc_object { +private: + isa_t isa; + +public: + + // ISA() assumes this is NOT a tagged pointer object + Class ISA(); + + // getIsa() allows this to be a tagged pointer object + Class getIsa(); + + // initIsa() should be used to init the isa of new objects only. + // If this object already has an isa, use changeIsa() for correctness. + // initInstanceIsa(): objects with no custom RR/AWZ + // initClassIsa(): class objects + // initProtocolIsa(): protocol objects + // initIsa(): other objects + void initIsa(Class cls /*indexed=false*/); + void initClassIsa(Class cls /*indexed=maybe*/); + void initProtocolIsa(Class cls /*indexed=maybe*/); + void initInstanceIsa(Class cls, bool hasCxxDtor); + + // changeIsa() should be used to change the isa of existing objects. + // If this is a new object, use initIsa() for performance. + Class changeIsa(Class newCls); + + bool hasIndexedIsa(); + bool isTaggedPointer(); + bool isClass(); + + // object may have associated objects? + bool hasAssociatedObjects(); + void setHasAssociatedObjects(); + + // object may be weakly referenced? + bool isWeaklyReferenced(); + void setWeaklyReferenced_nolock(); + + // object may have -.cxx_destruct implementation? + bool hasCxxDtor(); + + // Optimized calls to retain/release methods + id retain(); + void release(); + id autorelease(); + + // Implementations of retain/release methods + id rootRetain(); + bool rootRelease(); + id rootAutorelease(); + bool rootTryRetain(); + bool rootReleaseShouldDealloc(); + uintptr_t rootRetainCount(); + + // Implementation of dealloc methods + bool rootIsDeallocating(); + void clearDeallocating(); + void rootDealloc(); + +private: + void initIsa(Class newCls, bool indexed, bool hasCxxDtor); + + // Slow paths for inline control + id rootAutorelease2(); + bool overrelease_error(); + +#if SUPPORT_NONPOINTER_ISA + // Unified retain count manipulation for nonpointer isa + id rootRetain(bool tryRetain, bool handleOverflow); + bool rootRelease(bool performDealloc, bool handleUnderflow); + id rootRetain_overflow(bool tryRetain); + bool rootRelease_underflow(bool performDealloc); + + void clearDeallocating_weak(); + + // Side table retain count overflow for nonpointer isa + void sidetable_lock(); + void sidetable_unlock(); + + void sidetable_moveExtraRC_nolock(size_t extra_rc, bool isDeallocating, bool weaklyReferenced); + bool sidetable_addExtraRC_nolock(size_t delta_rc); + bool sidetable_subExtraRC_nolock(size_t delta_rc); + size_t sidetable_getExtraRC_nolock(); #endif - /* variable length structure */ - struct old_ivar ivar_list[1]; -}; + // Side-table-only retain count + bool sidetable_isDeallocating(); + void sidetable_clearDeallocating(); -struct old_method { - SEL method_name; - char *method_types; - IMP method_imp; -}; + bool sidetable_isWeaklyReferenced(); + void sidetable_setWeaklyReferenced_nolock(); -// Fixed-up method lists get mlist->obsolete = _OBJC_FIXED_UP. -#define _OBJC_FIXED_UP ((void *)1771) + id sidetable_retain(); + id sidetable_retain_slow(SideTable *table); -struct old_method_list { - struct old_method_list *obsolete; + bool sidetable_release(bool performDealloc = true); + bool sidetable_release_slow(SideTable *table, bool performDealloc = true); - int method_count; -#ifdef __LP64__ - int space; + bool sidetable_tryRetain(); + + uintptr_t sidetable_retainCount(); +#if !NDEBUG + bool sidetable_present(); #endif - /* variable length structure */ - struct old_method method_list[1]; }; -struct old_protocol { - Class isa; - const char *protocol_name; - struct old_protocol_list *protocol_list; - struct objc_method_description_list *instance_methods; - struct objc_method_description_list *class_methods; -}; -struct old_protocol_list { - struct old_protocol_list *next; - long count; - struct old_protocol *list[1]; -}; +#if __OBJC2__ +typedef struct method_t *Method; +typedef struct ivar_t *Ivar; +typedef struct category_t *Category; +typedef struct property_t *objc_property_t; +#else +typedef struct old_method *Method; +typedef struct old_ivar *Ivar; +typedef struct old_category *Category; +typedef struct old_property *objc_property_t; +#endif -struct old_protocol_ext { - uint32_t size; - struct objc_method_description_list *optional_instance_methods; - struct objc_method_description_list *optional_class_methods; - struct objc_property_list *instance_properties; -}; +// Public headers -#endif +#include "objc.h" +#include "runtime.h" +#include "objc-os.h" +#include "objc-abi.h" +#include "objc-api.h" +#include "objc-auto.h" +#include "objc-config.h" +#include "objc-internal.h" +#include "maptable.h" +#include "hashtable2.h" -typedef objc_property_t Property; +/* Do not include message.h here. */ +/* #include "message.h" */ -struct objc_property { - const char *name; - const char *attributes; -}; +#define __APPLE_API_PRIVATE +#include "objc-gdb.h" +#undef __APPLE_API_PRIVATE -struct objc_property_list { - uint32_t entsize; - uint32_t count; - struct objc_property first; -}; +// Private headers -#import "objc-api.h" -#import "objc-config.h" -#import "hashtable2.h" +#if __OBJC2__ +#include "objc-runtime-new.h" +#else +#include "objc-runtime-old.h" +#endif -#import "Object.h" +#include "objc-references.h" +#include "objc-initialize.h" +#include "objc-loadmethod.h" -#define mutex_alloc() (pthread_mutex_t*)calloc(1, sizeof(pthread_mutex_t)) -#define mutex_init(m) pthread_mutex_init(m, NULL) -#define mutex_lock(m) pthread_mutex_lock(m) -#define mutex_try_lock(m) (! pthread_mutex_trylock(m)) -#define mutex_unlock(m) pthread_mutex_unlock(m) -#define mutex_clear(m) -#define mutex_t pthread_mutex_t* -#define mutex MUTEX_DEFINE_ERROR +__BEGIN_DECLS -/* Opaque cookie used in _getObjc... routines. File format independant. - * This is used in place of the mach_header. In fact, when compiling - * for NEXTSTEP, this is really a (struct mach_header *). - * - * had been: typedef void *objc_header; - */ -#ifndef __LP64__ -typedef struct mach_header headerType; -typedef struct segment_command segmentType; -#else -typedef struct mach_header_64 headerType; -typedef struct segment_command_64 segmentType; -#endif -typedef struct { - uint32_t version; // currently 0 - uint32_t flags; -} objc_image_info; +#if (defined(OBJC_NO_GC) && SUPPORT_GC) || \ + (!defined(OBJC_NO_GC) && !SUPPORT_GC) +# error OBJC_NO_GC and SUPPORT_GC inconsistent +#endif -// masks for objc_image_info.flags -#define OBJC_IMAGE_IS_REPLACEMENT (1<<0) -#define OBJC_IMAGE_SUPPORTS_GC (1<<1) -#define OBJC_IMAGE_REQUIRES_GC (1<<2) +#if SUPPORT_GC +# include + // PRIVATE_EXTERN is needed to help the compiler know "how" extern these are + PRIVATE_EXTERN extern int8_t UseGC; // equivalent to calling objc_collecting_enabled() + PRIVATE_EXTERN extern auto_zone_t *gc_zone; // the GC zone, or NULL if no GC + extern void objc_addRegisteredClass(Class c); + extern void objc_removeRegisteredClass(Class c); +#else +# define UseGC NO +# define gc_zone NULL +# define objc_addRegisteredClass(c) do {} while(0) +# define objc_removeRegisteredClass(c) do {} while(0) + /* Uses of the following must be protected with UseGC. */ + extern id gc_unsupported_dont_call(); +# define auto_zone_allocate_object gc_unsupported_dont_call +# define auto_zone_retain gc_unsupported_dont_call +# define auto_zone_release gc_unsupported_dont_call +# define auto_zone_is_valid_pointer gc_unsupported_dont_call +# define auto_zone_write_barrier_memmove gc_unsupported_dont_call +# define AUTO_OBJECT_SCANNED 0 +#endif #define _objcHeaderIsReplacement(h) ((h)->info && ((h)->info->flags & OBJC_IMAGE_IS_REPLACEMENT)) @@ -222,7 +316,7 @@ typedef struct { Do fix up selector refs (@selector points to them) Do fix up class refs (@class and objc_msgSend points to them) Do fix up protocols (@protocol points to them) - Do fix up super_class pointers in classes ([super ...] points to them) + Do fix up superclass pointers in classes ([super ...] points to them) Future: do load new classes? Future: do load new categories? Future: do insert new methods on existing classes? @@ -239,247 +333,385 @@ typedef struct { if executable image compiled this way, then all subsequent libraries etc. must also be this way */ +#define _objcHeaderOptimizedByDyld(h) ((h)->info && ((h)->info->flags & OBJC_IMAGE_OPTIMIZED_BY_DYLD)) -typedef struct _header_info -{ +/* OBJC_IMAGE_OPTIMIZED_BY_DYLD: + Assorted metadata precooked in the dyld shared cache. + Never set for images outside the shared cache file itself. +*/ + + +typedef struct _header_info { struct _header_info *next; - const headerType * mhdr; - ptrdiff_t image_slide; - const segmentType * objcSegmentHeader; - const segmentType * dataSegmentHeader; - struct objc_module *mod_ptr; - size_t mod_count; + const headerType *mhdr; const objc_image_info *info; - Dl_info dl_info; - BOOL allClassesRealized; -} header_info; + const char *fname; // same as Dl_info.dli_fname + bool loaded; + bool inSharedCache; + bool allClassesRealized; + // Do not add fields without editing ObjCModernAbstraction.hpp -extern objc_image_info *_getObjcImageInfo(const headerType *head, ptrdiff_t slide, size_t *size); -extern const segmentType *getsegbynamefromheader(const headerType *head, const char *segname); -extern const char *_getObjcHeaderName(const headerType *head); -extern ptrdiff_t _getImageSlide(const headerType *header); - -extern Module _getObjcModules(const headerType *head, ptrdiff_t slide, size_t *count); -extern SEL *_getObjcSelectorRefs(const header_info *hi, size_t *count); #if !__OBJC2__ -extern struct old_protocol *_getObjcProtocols(const header_info *head, size_t *count); -extern struct old_class **_getObjcClassRefs(const header_info *hi, size_t *count); -extern const char *_getObjcClassNames(const header_info *hi, size_t *size); + struct old_protocol **proto_refs; + struct objc_module *mod_ptr; + size_t mod_count; +# if TARGET_OS_WIN32 + struct objc_module **modules; + size_t moduleCount; + struct old_protocol **protocols; + size_t protocolCount; + void *imageinfo; + size_t imageinfoBytes; + SEL *selrefs; + size_t selrefCount; + struct objc_class **clsrefs; + size_t clsrefCount; + TCHAR *moduleName; +# endif #endif +} header_info; -#if __OBJC2__ -extern SEL *_getObjc2SelectorRefs(const header_info *hi, size_t *count); -extern message_ref *_getObjc2MessageRefs(const header_info *hi, size_t *count);extern struct class_t **_getObjc2ClassRefs(const header_info *hi, size_t *count); -extern struct class_t **_getObjc2SuperRefs(const header_info *hi, size_t *count); -extern struct class_t **_getObjc2ClassList(const header_info *hi, size_t *count); -extern struct class_t **_getObjc2NonlazyClassList(const header_info *hi, size_t *count); -extern struct category_t **_getObjc2CategoryList(const header_info *hi, size_t *count); -extern struct category_t **_getObjc2NonlazyCategoryList(const header_info *hi, size_t *count); -extern struct protocol_t **_getObjc2ProtocolList(const header_info *head, size_t *count); -extern struct protocol_t **_getObjc2ProtocolRefs(const header_info *head, size_t *count); +extern header_info *FirstHeader; +extern header_info *LastHeader; +extern int HeaderCount; + +extern uint32_t AppSDKVersion; // X.Y.Z is 0xXXXXYYZZ + +extern void appendHeader(header_info *hi); +extern void removeHeader(header_info *hi); + +extern objc_image_info *_getObjcImageInfo(const headerType *head, size_t *size); +extern BOOL _hasObjcContents(const header_info *hi); + + +/* selectors */ +extern void sel_init(BOOL gc, size_t selrefCount); +extern SEL sel_registerNameNoLock(const char *str, BOOL copy); +extern void sel_lock(void); +extern void sel_unlock(void); +extern BOOL sel_preoptimizationValid(const header_info *hi); + +extern SEL SEL_load; +extern SEL SEL_initialize; +extern SEL SEL_resolveClassMethod; +extern SEL SEL_resolveInstanceMethod; +extern SEL SEL_cxx_construct; +extern SEL SEL_cxx_destruct; +extern SEL SEL_retain; +extern SEL SEL_release; +extern SEL SEL_autorelease; +extern SEL SEL_retainCount; +extern SEL SEL_alloc; +extern SEL SEL_allocWithZone; +extern SEL SEL_dealloc; +extern SEL SEL_copy; +extern SEL SEL_new; +extern SEL SEL_finalize; +extern SEL SEL_forwardInvocation; +extern SEL SEL_tryRetain; +extern SEL SEL_isDeallocating; +extern SEL SEL_retainWeakReference; +extern SEL SEL_allowsWeakReference; + +/* preoptimization */ +extern void preopt_init(void); +extern void disableSharedCacheOptimizations(void); +extern bool isPreoptimized(void); +extern header_info *preoptimizedHinfoForHeader(const headerType *mhdr); + +#if SUPPORT_PREOPT && __cplusplus +#include +using objc_selopt_t = const objc_opt::objc_selopt_t; +#else +struct objc_selopt_t; #endif -#define END_OF_METHODS_LIST ((struct old_method_list*)-1) - -OBJC_EXPORT header_info *_objc_headerStart (); - -OBJC_EXPORT const char *_nameForHeader(const headerType*); +extern objc_selopt_t *preoptimizedSelectors(void); +extern Class getPreoptimizedClass(const char *name); +extern Class* copyPreoptimizedClasses(const char *name, int *outCount); -OBJC_EXPORT SEL sel_registerNameNoLock(const char *str, BOOL copy); -OBJC_EXPORT void sel_lock(void); -OBJC_EXPORT void sel_unlock(void); /* optional malloc zone for runtime data */ -OBJC_EXPORT malloc_zone_t *_objc_internal_zone(void); -OBJC_EXPORT void *_malloc_internal(size_t size); -OBJC_EXPORT void *_calloc_internal(size_t count, size_t size); -OBJC_EXPORT void *_realloc_internal(void *ptr, size_t size); -OBJC_EXPORT char *_strdup_internal(const char *str); -OBJC_EXPORT char *_strdupcat_internal(const char *s1, const char *s2); -OBJC_EXPORT void *_memdup_internal(const void *mem, size_t size); -OBJC_EXPORT void _free_internal(void *ptr); - -#if !__OBJC2__ -OBJC_EXPORT Class objc_getOrigClass (const char *name); -OBJC_EXPORT IMP lookupNamedMethodInMethodList(struct old_method_list *mlist, const char *meth_name); -OBJC_EXPORT void _objc_insertMethods(struct old_class *cls, struct old_method_list *mlist, struct old_category *cat); -OBJC_EXPORT void _objc_removeMethods(struct old_class *cls, struct old_method_list *mlist); -OBJC_EXPORT void _objc_flush_caches (Class cls); -extern void _class_addProperties(struct old_class *cls, struct objc_property_list *additions); -extern void change_class_references(struct old_class *imposter, struct old_class *original, struct old_class *copy, BOOL changeSuperRefs); -extern void flush_marked_caches(void); -extern void set_superclass(struct old_class *cls, struct old_class *supercls); -#endif - -OBJC_EXPORT IMP _cache_getImp(Class cls, SEL sel); -OBJC_EXPORT Method _cache_getMethod(Class cls, SEL sel, IMP objc_msgForward_imp); +extern malloc_zone_t *_objc_internal_zone(void); +extern void *_malloc_internal(size_t size); +extern void *_calloc_internal(size_t count, size_t size); +extern void *_realloc_internal(void *ptr, size_t size); +extern char *_strdup_internal(const char *str); +extern char *_strdupcat_internal(const char *s1, const char *s2); +extern uint8_t *_ustrdup_internal(const uint8_t *str); +extern void *_memdup_internal(const void *mem, size_t size); +extern void _free_internal(void *ptr); +extern size_t _malloc_size_internal(void *ptr); + +extern Class _calloc_class(size_t size); + +/* method lookup */ +extern IMP lookUpImpOrNil(Class, SEL, id obj, bool initialize, bool cache, bool resolver); +extern IMP lookUpImpOrForward(Class, SEL, id obj, bool initialize, bool cache, bool resolver); + +extern IMP lookupMethodInClassAndLoadCache(Class cls, SEL sel); +extern BOOL class_respondsToSelector_inst(Class cls, SEL sel, id inst); + +extern bool objcMsgLogEnabled; +extern bool logMessageSend(bool isClassMethod, + const char *objectsClass, + const char *implementingClass, + SEL selector); /* message dispatcher */ -OBJC_EXPORT IMP _class_lookupMethodAndLoadCache(Class, SEL); -OBJC_EXPORT id _objc_msgForward (id self, SEL sel, ...); -extern id _objc_ignored_method(id self, SEL _cmd); +extern IMP _class_lookupMethodAndLoadCache3(id, SEL, Class); + +#if !OBJC_OLD_DISPATCH_PROTOTYPES +extern void _objc_msgForward_impcache(void); +extern void _objc_ignored_method(void); +extern void _objc_msgSend_uncached_impcache(void); +#else +extern id _objc_msgForward_impcache(id, SEL, ...); +extern id _objc_ignored_method(id, SEL, ...); +extern id _objc_msgSend_uncached_impcache(id, SEL, ...); +#endif /* errors */ -OBJC_EXPORT void _objc_fatal(const char *fmt, ...) __attribute__((noreturn, format (printf, 1, 2))); -OBJC_EXPORT void __objc_error(id, const char *, ...) __attribute__((format (printf, 2, 3))); -OBJC_EXPORT void _objc_inform(const char *fmt, ...) __attribute__((format (printf, 1, 2))); -OBJC_EXPORT void _objc_inform_on_crash(const char *fmt, ...) __attribute__((format (printf, 1, 2))); -OBJC_EXPORT void _objc_inform_now_and_on_crash(const char *fmt, ...) __attribute__((format (printf, 1, 2))); -OBJC_EXPORT void _objc_warn_deprecated(const char *old, const char *new) __attribute__((noinline)); -OBJC_EXPORT void _objc_error(id, const char *, va_list); +extern void __objc_error(id, const char *, ...) __attribute__((format (printf, 2, 3), noreturn)); +extern void _objc_inform(const char *fmt, ...) __attribute__((format (printf, 1, 2))); +extern void _objc_inform_on_crash(const char *fmt, ...) __attribute__((format (printf, 1, 2))); +extern void _objc_inform_now_and_on_crash(const char *fmt, ...) __attribute__((format (printf, 1, 2))); +extern void _objc_inform_deprecated(const char *oldname, const char *newname) __attribute__((noinline)); +extern void inform_duplicate(const char *name, Class oldCls, Class cls); +extern bool crashlog_header_name(header_info *hi); +extern bool crashlog_header_name_string(const char *name); /* magic */ -OBJC_EXPORT Class _objc_getFreedObjectClass (void); -#ifndef OBJC_INSTRUMENTED -OBJC_EXPORT const struct objc_cache _objc_empty_cache; -#else -OBJC_EXPORT struct objc_cache _objc_empty_cache; -#endif -#if __OBJC2__ -extern IMP _objc_empty_vtable[128]; -#endif +extern Class _objc_getFreedObjectClass (void); /* map table additions */ extern void *NXMapKeyCopyingInsert(NXMapTable *table, const void *key, const void *value); extern void *NXMapKeyFreeingRemove(NXMapTable *table, const void *key); +/* hash table additions */ +extern unsigned _NXHashCapacity(NXHashTable *table); +extern void _NXHashRehashToCapacity(NXHashTable *table, unsigned newCapacity); + +/* property attribute parsing */ +extern const char *copyPropertyAttributeString(const objc_property_attribute_t *attrs, unsigned int count); +extern objc_property_attribute_t *copyPropertyAttributeList(const char *attrs, unsigned int *outCount); +extern char *copyPropertyAttributeValue(const char *attrs, const char *name); + /* locking */ -#define OBJC_DECLARE_LOCK(MTX) pthread_mutex_t MTX = PTHREAD_MUTEX_INITIALIZER -#ifdef NDEBUG -#define OBJC_LOCK(MUTEX) mutex_lock (MUTEX) -#define OBJC_UNLOCK(MUTEX) mutex_unlock (MUTEX) -#define OBJC_CHECK_LOCKED(MUTEX) do { } while (0) -#define OBJC_CHECK_UNLOCKED(MUTEX) do { } while (0) +extern void lock_init(void); +extern rwlock_t selLock; +extern mutex_t cacheUpdateLock; +extern recursive_mutex_t loadMethodLock; +#if __OBJC2__ +extern rwlock_t runtimeLock; +#else +extern mutex_t classLock; +extern mutex_t methodListLock; +#endif + +/* Lock debugging */ +#if defined(NDEBUG) || TARGET_OS_WIN32 + +#define mutex_lock(m) _mutex_lock_nodebug(m) +#define mutex_try_lock(m) _mutex_try_lock_nodebug(m) +#define mutex_unlock(m) _mutex_unlock_nodebug(m) +#define mutex_assert_locked(m) do { } while (0) +#define mutex_assert_unlocked(m) do { } while (0) + +#define recursive_mutex_lock(m) _recursive_mutex_lock_nodebug(m) +#define recursive_mutex_try_lock(m) _recursive_mutex_try_lock_nodebug(m) +#define recursive_mutex_unlock(m) _recursive_mutex_unlock_nodebug(m) +#define recursive_mutex_assert_locked(m) do { } while (0) +#define recursive_mutex_assert_unlocked(m) do { } while (0) + +#define monitor_enter(m) _monitor_enter_nodebug(m) +#define monitor_exit(m) _monitor_exit_nodebug(m) +#define monitor_wait(m) _monitor_wait_nodebug(m) +#define monitor_assert_locked(m) do { } while (0) +#define monitor_assert_unlocked(m) do { } while (0) + +#define rwlock_read(m) _rwlock_read_nodebug(m) +#define rwlock_write(m) _rwlock_write_nodebug(m) +#define rwlock_try_read(m) _rwlock_try_read_nodebug(m) +#define rwlock_try_write(m) _rwlock_try_write_nodebug(m) +#define rwlock_unlock_read(m) _rwlock_unlock_read_nodebug(m) +#define rwlock_unlock_write(m) _rwlock_unlock_write_nodebug(m) +#define rwlock_assert_reading(m) do { } while (0) +#define rwlock_assert_writing(m) do { } while (0) +#define rwlock_assert_locked(m) do { } while (0) +#define rwlock_assert_unlocked(m) do { } while (0) + #else -#define OBJC_LOCK(MUTEX) _lock_debug (MUTEX, #MUTEX) -#define OBJC_UNLOCK(MUTEX) _unlock_debug (MUTEX, #MUTEX) -#define OBJC_CHECK_LOCKED(MUTEX) _checklock_debug (MUTEX, #MUTEX) -#define OBJC_CHECK_UNLOCKED(MUTEX) _checkunlock_debug (MUTEX, #MUTEX) + +extern int _mutex_lock_debug(mutex_t *lock, const char *name); +extern int _mutex_try_lock_debug(mutex_t *lock, const char *name); +extern int _mutex_unlock_debug(mutex_t *lock, const char *name); +extern void _mutex_assert_locked_debug(mutex_t *lock, const char *name); +extern void _mutex_assert_unlocked_debug(mutex_t *lock, const char *name); + +extern int _recursive_mutex_lock_debug(recursive_mutex_t *lock, const char *name); +extern int _recursive_mutex_try_lock_debug(recursive_mutex_t *lock, const char *name); +extern int _recursive_mutex_unlock_debug(recursive_mutex_t *lock, const char *name); +extern void _recursive_mutex_assert_locked_debug(recursive_mutex_t *lock, const char *name); +extern void _recursive_mutex_assert_unlocked_debug(recursive_mutex_t *lock, const char *name); + +extern int _monitor_enter_debug(monitor_t *lock, const char *name); +extern int _monitor_exit_debug(monitor_t *lock, const char *name); +extern int _monitor_wait_debug(monitor_t *lock, const char *name); +extern void _monitor_assert_locked_debug(monitor_t *lock, const char *name); +extern void _monitor_assert_unlocked_debug(monitor_t *lock, const char *name); + +extern void _rwlock_read_debug(rwlock_t *l, const char *name); +extern void _rwlock_write_debug(rwlock_t *l, const char *name); +extern int _rwlock_try_read_debug(rwlock_t *l, const char *name); +extern int _rwlock_try_write_debug(rwlock_t *l, const char *name); +extern void _rwlock_unlock_read_debug(rwlock_t *l, const char *name); +extern void _rwlock_unlock_write_debug(rwlock_t *l, const char *name); +extern void _rwlock_assert_reading_debug(rwlock_t *l, const char *name); +extern void _rwlock_assert_writing_debug(rwlock_t *l, const char *name); +extern void _rwlock_assert_locked_debug(rwlock_t *l, const char *name); +extern void _rwlock_assert_unlocked_debug(rwlock_t *l, const char *name); + +#define mutex_lock(m) _mutex_lock_debug (m, #m) +#define mutex_try_lock(m) _mutex_try_lock_debug (m, #m) +#define mutex_unlock(m) _mutex_unlock_debug (m, #m) +#define mutex_assert_locked(m) _mutex_assert_locked_debug (m, #m) +#define mutex_assert_unlocked(m) _mutex_assert_unlocked_debug (m, #m) + +#define recursive_mutex_lock(m) _recursive_mutex_lock_debug (m, #m) +#define recursive_mutex_try_lock(m) _recursive_mutex_try_lock_debug (m, #m) +#define recursive_mutex_unlock(m) _recursive_mutex_unlock_debug (m, #m) +#define recursive_mutex_assert_locked(m) _recursive_mutex_assert_locked_debug (m, #m) +#define recursive_mutex_assert_unlocked(m) _recursive_mutex_assert_unlocked_debug (m, #m) + +#define monitor_enter(m) _monitor_enter_debug(m, #m) +#define monitor_exit(m) _monitor_exit_debug(m, #m) +#define monitor_wait(m) _monitor_wait_debug(m, #m) +#define monitor_assert_locked(m) _monitor_assert_locked_debug(m, #m) +#define monitor_assert_unlocked(m) _monitor_assert_unlocked_debug(m, #m) + +#define rwlock_read(m) _rwlock_read_debug(m, #m) +#define rwlock_write(m) _rwlock_write_debug(m, #m) +#define rwlock_try_read(m) _rwlock_try_read_debug(m, #m) +#define rwlock_try_write(m) _rwlock_try_write_debug(m, #m) +#define rwlock_unlock_read(m) _rwlock_unlock_read_debug(m, #m) +#define rwlock_unlock_write(m) _rwlock_unlock_write_debug(m, #m) +#define rwlock_assert_reading(m) _rwlock_assert_reading_debug(m, #m) +#define rwlock_assert_writing(m) _rwlock_assert_writing_debug(m, #m) +#define rwlock_assert_locked(m) _rwlock_assert_locked_debug(m, #m) +#define rwlock_assert_unlocked(m) _rwlock_assert_unlocked_debug(m, #m) + #endif -OBJC_EXPORT pthread_mutex_t classLock; -OBJC_EXPORT pthread_mutex_t methodListLock; +#define rwlock_unlock(m, s) \ + do { \ + if ((s) == RDONLY) rwlock_unlock_read(m); \ + else if ((s) == RDWR) rwlock_unlock_write(m); \ + } while (0) -OBJC_EXPORT NXHashTable *class_hash; -/* nil handler object */ -OBJC_EXPORT id _objc_nilReceiver; -OBJC_EXPORT id _objc_setNilReceiver(id newNilReceiver); -OBJC_EXPORT id _objc_getNilReceiver(void); +/* ignored selector support */ -/* forward handler functions */ -OBJC_EXPORT void *_objc_forward_handler; -OBJC_EXPORT void *_objc_forward_stret_handler; +/* Non-GC: no ignored selectors + GC (i386 Mac): some selectors ignored, remapped to kIgnore + GC (others): some selectors ignored, but not remapped +*/ -/* C++ interoperability */ -OBJC_EXPORT SEL cxx_construct_sel; -OBJC_EXPORT SEL cxx_destruct_sel; -OBJC_EXPORT const char *cxx_construct_name; -OBJC_EXPORT const char *cxx_destruct_name; +static inline int ignoreSelector(SEL sel) +{ +#if !SUPPORT_GC + return NO; +#elif SUPPORT_IGNORED_SELECTOR_CONSTANT + return UseGC && sel == (SEL)kIgnore; +#else + return UseGC && + (sel == @selector(retain) || + sel == @selector(release) || + sel == @selector(autorelease) || + sel == @selector(retainCount) || + sel == @selector(dealloc)); +#endif +} + +static inline int ignoreSelectorNamed(const char *sel) +{ +#if !SUPPORT_GC + return NO; +#else + // release retain retainCount dealloc autorelease + return (UseGC && + ( (sel[0] == 'r' && sel[1] == 'e' && + (strcmp(&sel[2], "lease") == 0 || + strcmp(&sel[2], "tain") == 0 || + strcmp(&sel[2], "tainCount") == 0 )) + || + (strcmp(sel, "dealloc") == 0) + || + (sel[0] == 'a' && sel[1] == 'u' && + strcmp(&sel[2], "torelease") == 0))); +#endif +} -/* GC and RTP startup */ -OBJC_EXPORT void gc_init(BOOL on); -OBJC_EXPORT void rtp_init(void); +/* GC startup */ +extern void gc_init(BOOL wantsGC); +extern void gc_init2(void); /* Exceptions */ struct alt_handler_list; -OBJC_EXPORT void exception_init(void); -OBJC_EXPORT void _destroyAltHandlerList(struct alt_handler_list *list); +extern void exception_init(void); +extern void _destroyAltHandlerList(struct alt_handler_list *list); -/* Write barrier implementations */ -OBJC_EXPORT id objc_assign_strongCast_gc(id val, id *dest); -OBJC_EXPORT id objc_assign_global_gc(id val, id *dest); -OBJC_EXPORT id objc_assign_ivar_gc(id value, id dest, ptrdiff_t offset); -OBJC_EXPORT id objc_assign_strongCast_non_gc(id value, id *dest); -OBJC_EXPORT id objc_assign_global_non_gc(id value, id *dest); -OBJC_EXPORT id objc_assign_ivar_non_gc(id value, id dest, ptrdiff_t offset); +/* Class change notifications (gdb only for now) */ +#define OBJC_CLASS_ADDED (1<<0) +#define OBJC_CLASS_REMOVED (1<<1) +#define OBJC_CLASS_IVARS_CHANGED (1<<2) +#define OBJC_CLASS_METHODS_CHANGED (1<<3) +extern void gdb_objc_class_changed(Class cls, unsigned long changes, const char *classname) + __attribute__((noinline)); -/* - objc_assign_ivar, objc_assign_global, and objc_assign_strongCast MUST NOT be called directly - from inside libobjc. They live in the data segment, and must be called through the - following pointer(s) for libobjc to exist in the shared cache. +#if SUPPORT_GC - Note: If we build with GC enabled, gcc will emit calls to the original functions, which will break this. -*/ +/* Write barrier implementations */ +extern id objc_getAssociatedObject_non_gc(id object, const void *key); +extern void objc_setAssociatedObject_non_gc(id object, const void *key, id value, objc_AssociationPolicy policy); -extern id (*objc_assign_ivar_internal)(id, id, ptrdiff_t); - -/* Code modification */ -OBJC_EXPORT size_t objc_branch_size(void *entry, void *target); -OBJC_EXPORT size_t objc_write_branch(void *entry, void *target); -OBJC_EXPORT size_t objc_cond_branch_size(void *entry, void *target, unsigned cond); -OBJC_EXPORT size_t objc_write_cond_branch(void *entry, void *target, unsigned cond); -#if defined(__ppc__) || defined(__ppc64__) -#define COND_ALWAYS 0x02800000 /* BO=10100, BI=00000 */ -#define COND_NE 0x00820000 /* BO=00100, BI=00010 */ -#elif defined(__i386__) || defined(__x86_64__) -#define COND_ALWAYS 0xE9 /* JMP rel32 */ -#define COND_NE 0x85 /* JNE rel32 (0F 85) */ -#endif +extern id objc_getAssociatedObject_gc(id object, const void *key); +extern void objc_setAssociatedObject_gc(id object, const void *key, id value, objc_AssociationPolicy policy); +/* xrefs */ +extern objc_xref_t _object_addExternalReference_non_gc(id obj, objc_xref_t type); +extern id _object_readExternalReference_non_gc(objc_xref_t ref); +extern void _object_removeExternalReference_non_gc(objc_xref_t ref); -/* Thread-safe info field */ -#if !__OBJC2__ -OBJC_EXPORT void _class_setInfo(Class cls, long set); -OBJC_EXPORT void _class_clearInfo(Class cls, long clear); -OBJC_EXPORT void _class_changeInfo(Class cls, long set, long clear); -#endif +extern objc_xref_t _object_addExternalReference_gc(id obj, objc_xref_t type); +extern id _object_readExternalReference_gc(objc_xref_t ref); +extern void _object_removeExternalReference_gc(objc_xref_t ref); -/* Secure /tmp usage */ -OBJC_EXPORT int secure_open(const char *filename, int flags, uid_t euid); +/* GC weak reference fixup. */ +extern void gc_fixup_weakreferences(id newObject, id oldObject); +/* GC datasegment registration. */ +extern void gc_register_datasegment(uintptr_t base, size_t size); +extern void gc_unregister_datasegment(uintptr_t base, size_t size); + +/* objc_dumpHeap implementation */ +extern BOOL _objc_dumpHeap(auto_zone_t *zone, const char *filename); -#if !defined(SEG_OBJC) -#define SEG_OBJC "__OBJC" /* objective-C runtime segment */ -#endif -#if !defined(SEG_OBJC2) -#define SEG_OBJC2 "__OBJC2" #endif // Settings from environment variables -OBJC_EXPORT int PrintImages; // env OBJC_PRINT_IMAGES -OBJC_EXPORT int PrintLoading; // env OBJC_PRINT_LOAD_METHODS -OBJC_EXPORT int PrintInitializing; // env OBJC_PRINT_INITIALIZE_METHODS -OBJC_EXPORT int PrintResolving; // env OBJC_PRINT_RESOLVED_METHODS -OBJC_EXPORT int PrintConnecting; // env OBJC_PRINT_CLASS_SETUP -OBJC_EXPORT int PrintProtocols; // env OBJC_PRINT_PROTOCOL_SETUP -OBJC_EXPORT int PrintIvars; // env OBJC_PRINT_IVAR_SETUP -OBJC_EXPORT int PrintFuture; // env OBJC_PRINT_FUTURE_CLASSES -OBJC_EXPORT int PrintRTP; // env OBJC_PRINT_RTP -OBJC_EXPORT int PrintGC; // env OBJC_PRINT_GC -OBJC_EXPORT int PrintSharing; // env OBJC_PRINT_SHARING -OBJC_EXPORT int PrintCxxCtors; // env OBJC_PRINT_CXX_CTORS -OBJC_EXPORT int PrintExceptions; // env OBJC_PRINT_EXCEPTIONS -OBJC_EXPORT int PrintAltHandlers; // env OBJC_PRINT_ALT_HANDLERS -OBJC_EXPORT int PrintDeprecation;// env OBJC_PRINT_DEPRECATION_WARNINGS -OBJC_EXPORT int PrintReplacedMethods; // env OBJC_PRINT_REPLACED_METHODS -OBJC_EXPORT int PrintCacheCollection; // env OBJC_PRINT_CACHE_COLLECTION -OBJC_EXPORT int UseInternalZone; // env OBJC_USE_INTERNAL_ZONE -OBJC_EXPORT int AllowInterposing;// env OBJC_ALLOW_INTERPOSING - -OBJC_EXPORT int DebugUnload; // env OBJC_DEBUG_UNLOAD -OBJC_EXPORT int DebugFragileSuperclasses; // env OBJC_DEBUG_FRAGILE_SUPERCLASSES -OBJC_EXPORT int DebugFinalizers; // env OBJC_DEBUG_FINALIZERS -OBJC_EXPORT int DebugNilSync; // env OBJC_DEBUG_NIL_SYNC - -OBJC_EXPORT int DisableGC; // env OBJC_DISABLE_GC - -/* GC state */ -OBJC_EXPORT BOOL UseGC; // equivalent to calling objc_collecting_enabled() -OBJC_EXPORT auto_zone_t *gc_zone; // the GC zone, or NULL if no GC - -static __inline__ int _objc_strcmp(const char *s1, const char *s2) { - char c1, c2; - for ( ; (c1 = *s1) == (c2 = *s2); s1++, s2++) - if (c1 == '\0') - return 0; - return (c1 - c2); -} - -static __inline__ uintptr_t _objc_strhash(const char *s) { - uintptr_t hash = 0; +#define OPTION(var, env, help) extern bool var; +#include "objc-env.h" +#undef OPTION + +extern void environ_init(void); + +extern void logReplacedMethod(const char *className, SEL s, BOOL isMeta, const char *catName, IMP oldImp, IMP newImp); + +static __inline uint32_t _objc_strhash(const char *s) { + uint32_t hash = 0; for (;;) { int a = *s++; if (0 == a) break; @@ -492,75 +724,37 @@ static __inline__ uintptr_t _objc_strhash(const char *s) { // objc per-thread storage typedef struct { struct _objc_initializing_classes *initializingClasses; // for +initialize - struct _objc_lock_list *lockList; // for lock debugging struct SyncCache *syncCache; // for @synchronize struct alt_handler_list *handlerList; // for exception alt handlers + char *printableNames[4]; // temporary demangled names for logging // If you add new fields here, don't forget to update // _objc_pthread_destroyspecific() } _objc_pthread_data; -OBJC_EXPORT _objc_pthread_data *_objc_fetch_pthread_data(BOOL create); - - -// Class state -#if !__OBJC2__ -#define ISCLASS(cls) (((cls)->info & CLS_CLASS) != 0) -#define ISMETA(cls) (((cls)->info & CLS_META) != 0) -#define GETMETA(cls) (ISMETA(cls) ? (cls) : (cls)->isa) -#endif - - -// Attribute for global variables to keep them out of bss storage -// To save one page per non-Objective-C process, variables used in -// the "Objective-C not used" case should not be in bss storage. -// On Tiger, this reduces the number of touched pages for each -// CoreFoundation-only process from three to two. See #3857126 and #3857136. -#define NOBSS __attribute__((section("__DATA,__data"))) - -// cache.h -extern void flush_caches(Class cls, BOOL flush_meta); -extern void flush_cache(Class cls); -extern BOOL _cache_fill(Class cls, Method smt, SEL sel); -extern void _cache_addForwardEntry(Class cls, SEL sel); -extern void _cache_free(Cache cache); -#if !__OBJC2__ -// used by flush_caches outside objc-cache.m -extern void _cache_flush(Class cls); -extern pthread_mutex_t cacheUpdateLock; -#ifdef OBJC_INSTRUMENTED -extern unsigned int LinearFlushCachesCount; -extern unsigned int LinearFlushCachesVisitedCount; -extern unsigned int MaxLinearFlushCachesVisitedCount; -extern unsigned int NonlinearFlushCachesCount; -extern unsigned int NonlinearFlushCachesClassCount; -extern unsigned int NonlinearFlushCachesVisitedCount; -extern unsigned int MaxNonlinearFlushCachesVisitedCount; -extern unsigned int IdealFlushCachesCount; -extern unsigned int MaxIdealFlushCachesCount; -#endif -#endif +extern _objc_pthread_data *_objc_fetch_pthread_data(BOOL create); +extern void tls_init(void); // encoding.h extern unsigned int encoding_getNumberOfArguments(const char *typedesc); extern unsigned int encoding_getSizeOfArguments(const char *typedesc); -extern unsigned int encoding_getArgumentInfo(const char *typedesc, int arg, const char **type, int *offset); +extern unsigned int encoding_getArgumentInfo(const char *typedesc, unsigned int arg, const char **type, int *offset); extern void encoding_getReturnType(const char *t, char *dst, size_t dst_len); extern char * encoding_copyReturnType(const char *t); extern void encoding_getArgumentType(const char *t, unsigned int index, char *dst, size_t dst_len); extern char *encoding_copyArgumentType(const char *t, unsigned int index); -// lock.h -extern void _lock_debug(mutex_t lock, const char *name); -extern void _checklock_debug(mutex_t lock, const char *name); -extern void _checkunlock_debug(mutex_t lock, const char *name); -extern void _unlock_debug(mutex_t lock, const char *name); -extern void _destroyLockList(struct _objc_lock_list *locks); - // sync.h extern void _destroySyncCache(struct SyncCache *cache); +// arr +extern void arr_init(void); +extern id objc_autoreleaseReturnValue(id obj); + +// block trampolines +extern IMP _imp_implementationWithBlockNoCopy(id block); + // layout.h typedef struct { uint8_t *bits; @@ -569,147 +763,199 @@ typedef struct { BOOL weak; } layout_bitmap; extern layout_bitmap layout_bitmap_create(const unsigned char *layout_string, size_t layoutStringInstanceSize, size_t instanceSize, BOOL weak); +extern layout_bitmap layout_bitmap_create_empty(size_t instanceSize, BOOL weak); extern void layout_bitmap_free(layout_bitmap bits); extern const unsigned char *layout_string_create(layout_bitmap bits); extern void layout_bitmap_set_ivar(layout_bitmap bits, const char *type, size_t offset); extern void layout_bitmap_grow(layout_bitmap *bits, size_t newCount); extern void layout_bitmap_slide(layout_bitmap *bits, size_t oldPos, size_t newPos); +extern void layout_bitmap_slide_anywhere(layout_bitmap *bits, size_t oldPos, size_t newPos); extern BOOL layout_bitmap_splat(layout_bitmap dst, layout_bitmap src, size_t oldSrcInstanceSize); extern BOOL layout_bitmap_or(layout_bitmap dst, layout_bitmap src, const char *msg); +extern BOOL layout_bitmap_clear(layout_bitmap dst, layout_bitmap src, const char *msg); +extern void layout_bitmap_print(layout_bitmap bits); // fixme runtime -extern id look_up_class(const char *aClassName, BOOL includeUnconnected, BOOL includeClassHandler); +extern Class look_up_class(const char *aClassName, BOOL includeUnconnected, BOOL includeClassHandler); +extern const char *map_images(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info infoList[]); +extern const char *map_images_nolock(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info infoList[]); +extern const char * load_images(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info infoList[]); +extern BOOL load_images_nolock(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info infoList[]); +extern void unmap_image(const struct mach_header *mh, intptr_t vmaddr_slide); +extern void unmap_image_nolock(const struct mach_header *mh); extern void _read_images(header_info **hList, uint32_t hCount); extern void prepare_load_methods(header_info *hi); extern void _unload_image(header_info *hi); extern const char ** _objc_copyClassNamesForImage(header_info *hi, unsigned int *outCount); -extern Class _objc_allocateFutureClass(const char *name); - - -extern Property *copyPropertyList(struct objc_property_list *plist, unsigned int *outCount); - extern const header_info *_headerForClass(Class cls); -// fixme class -extern Property property_list_nth(const struct objc_property_list *plist, uint32_t i); -extern size_t property_list_size(const struct objc_property_list *plist); - -extern Class _class_getSuperclass(Class cls); -extern BOOL _class_getInfo(Class cls, int info); -extern const char *_class_getName(Class cls); -extern size_t _class_getInstanceSize(Class cls); -extern Class _class_getMeta(Class cls); -extern BOOL _class_isMetaClass(Class cls); -extern Cache _class_getCache(Class cls); -extern void _class_setCache(Class cls, Cache cache); -extern BOOL _class_isInitializing(Class cls); -extern BOOL _class_isInitialized(Class cls); -extern void _class_setInitializing(Class cls); -extern void _class_setInitialized(Class cls); -extern Class _class_getNonMetaClass(Class cls); -extern Method _class_getMethodNoSuper(Class cls, SEL sel); -extern Method _class_getMethod(Class cls, SEL sel); -extern BOOL _class_isLoadable(Class cls); -extern IMP _class_getLoadMethod(Class cls); -extern BOOL _class_hasLoadMethod(Class cls); -extern BOOL _class_hasCxxStructorsNoSuper(Class cls); -extern BOOL _class_shouldFinalizeOnMainThread(Class cls); -extern void _class_setFinalizeOnMainThread(Class cls); -extern BOOL _class_shouldGrowCache(Class cls); -extern void _class_setGrowCache(Class cls, BOOL grow); -extern Ivar _class_getVariable(Class cls, const char *name); -extern Class _class_getFreedObjectClass(void); -extern Class _class_getNonexistentObjectClass(void); -extern id _internal_class_createInstanceFromZone(Class cls, size_t extraBytes, - void *zone); -extern id _internal_object_dispose(id anObject); +extern Class _class_remap(Class cls); +extern Class _class_getNonMetaClass(Class cls, id obj); +extern Ivar _class_getVariable(Class cls, const char *name, Class *memberOf); +extern BOOL _class_usesAutomaticRetainRelease(Class cls); +extern uint32_t _class_getInstanceStart(Class cls); +extern unsigned _class_createInstancesFromZone(Class cls, size_t extraBytes, void *zone, id *results, unsigned num_requested); +extern id _objc_constructOrFree(id bytes, Class cls); extern const char *_category_getName(Category cat); extern const char *_category_getClassName(Category cat); extern Class _category_getClass(Category cat); extern IMP _category_getLoadMethod(Category cat); -#if !__OBJC2__ -#define oldcls(cls) ((struct old_class *)cls) -#define oldprotocol(proto) ((struct old_protocol *)proto) -#define oldmethod(meth) ((struct old_method *)meth) -#define oldcategory(cat) ((struct old_category *)cat) -#define oldivar(ivar) ((struct old_ivar *)ivar) - -static inline struct old_method *_method_asOld(Method m) { return (struct old_method *)m; } -static inline struct old_class *_class_asOld(Class cls) { return (struct old_class *)cls; } -static inline struct old_category *_category_asOld(Category cat) { return (struct old_category *)cat; } - -extern void unload_class(struct old_class *cls); -#endif - -extern BOOL object_cxxConstruct(id obj); +extern id object_cxxConstructFromClass(id obj, Class cls); extern void object_cxxDestruct(id obj); -#if !__OBJC2__ -#define CLS_CLASS 0x1 -#define CLS_META 0x2 -#define CLS_INITIALIZED 0x4 -#define CLS_POSING 0x8 -#define CLS_MAPPED 0x10 -#define CLS_FLUSH_CACHE 0x20 -#define CLS_GROW_CACHE 0x40 -#define CLS_NEED_BIND 0x80 -#define CLS_METHOD_ARRAY 0x100 -// the JavaBridge constructs classes with these markers -#define CLS_JAVA_HYBRID 0x200 -#define CLS_JAVA_CLASS 0x400 -// thread-safe +initialize -#define CLS_INITIALIZING 0x800 -// bundle unloading -#define CLS_FROM_BUNDLE 0x1000 -// C++ ivar support -#define CLS_HAS_CXX_STRUCTORS 0x2000 -// Lazy method list arrays -#define CLS_NO_METHOD_ARRAY 0x4000 -// +load implementation -#define CLS_HAS_LOAD_METHOD 0x8000 -// objc_allocateClassPair API -#define CLS_CONSTRUCTING 0x10000 -// visibility=hidden -#define CLS_HIDDEN 0x20000 -// GC: class has unsafe finalize method -#define CLS_FINALIZE_ON_MAIN_THREAD 0x40000 -// Lazy property list arrays -#define CLS_NO_PROPERTY_ARRAY 0x80000 -// +load implementation -#define CLS_CONNECTED 0x100000 -#define CLS_LOADED 0x200000 -// objc_allocateClassPair API -#define CLS_CONSTRUCTED 0x400000 -// class is leaf for cache flushing -#define CLS_LEAF 0x800000 -#endif +extern void _class_resolveMethod(Class cls, SEL sel, id inst); #define OBJC_WARN_DEPRECATED \ do { \ static int warned = 0; \ if (!warned) { \ warned = 1; \ - _objc_warn_deprecated(__FUNCTION__, NULL); \ + _objc_inform_deprecated(__FUNCTION__, NULL); \ } \ } while (0) \ -/* Method prototypes */ -@interface DoesNotExist -+ class; -+ initialize; -- (id)description; -- (const char *)UTF8String; -- (unsigned long)hash; -- (BOOL)isEqual:(id)object; -- free; -@end +__END_DECLS + + +#ifndef STATIC_ASSERT +# define STATIC_ASSERT(x) _STATIC_ASSERT2(x, __LINE__) +# define _STATIC_ASSERT2(x, line) _STATIC_ASSERT3(x, line) +# define _STATIC_ASSERT3(x, line) \ + typedef struct { \ + int _static_assert[(x) ? 0 : -1]; \ + } _static_assert_ ## line __attribute__((unavailable)) +#endif + +#define countof(arr) (sizeof(arr) / sizeof((arr)[0])) + + +// Global operator new and delete. We must not use any app overrides. +// This ALSO REQUIRES each of these be in libobjc's unexported symbol list. +#if __cplusplus +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winline-new-delete" +#include +inline void* operator new(std::size_t size) throw (std::bad_alloc) { return _malloc_internal(size); } +inline void* operator new[](std::size_t size) throw (std::bad_alloc) { return _malloc_internal(size); } +inline void* operator new(std::size_t size, const std::nothrow_t&) throw() { return _malloc_internal(size); } +inline void* operator new[](std::size_t size, const std::nothrow_t&) throw() { return _malloc_internal(size); } +inline void operator delete(void* p) throw() { _free_internal(p); } +inline void operator delete[](void* p) throw() { _free_internal(p); } +inline void operator delete(void* p, const std::nothrow_t&) throw() { _free_internal(p); } +inline void operator delete[](void* p, const std::nothrow_t&) throw() { _free_internal(p); } +#pragma clang diagnostic pop +#endif + + +// DisguisedPtr acts like pointer type T*, except the +// stored value is disguised to hide it from tools like `leaks`. +// nil is disguised as itself so zero-filled memory works as expected, +// which means 0x80..00 is also diguised as itself but we don't care +template +class DisguisedPtr { + uintptr_t value; + + static uintptr_t disguise(T* ptr) { + return -(uintptr_t)ptr; + } + + static T* undisguise(uintptr_t val) { + return (T*)-val; + } + + public: + DisguisedPtr() { } + DisguisedPtr(T* ptr) + : value(disguise(ptr)) { } + DisguisedPtr(const DisguisedPtr& ptr) + : value(ptr.value) { } + + DisguisedPtr& operator = (T* rhs) { + value = disguise(rhs); + return *this; + } + DisguisedPtr& operator = (const DisguisedPtr& rhs) { + value = rhs.value; + return *this; + } + + operator T* () const { + return undisguise(value); + } + T* operator -> () const { + return undisguise(value); + } + T& operator * () const { + return *undisguise(value); + } + T& operator [] (size_t i) const { + return undisguise(value)[i]; + } + + // pointer arithmetic operators omitted + // because we don't currently use them anywhere +}; + + +// Pointer hash function. +// This is not a terrific hash, but it is fast +// and not outrageously flawed for our purposes. + +// Based on principles from http://locklessinc.com/articles/fast_hash/ +// and evaluation ideas from http://floodyberry.com/noncryptohashzoo/ +#if __LP64__ +static inline uint32_t ptr_hash(uint64_t key) +{ + key ^= key >> 4; + key *= 0x8a970be7488fda55; + key ^= __builtin_bswap64(key); + return (uint32_t)key; +} +#else +static inline uint32_t ptr_hash(uint32_t key) +{ + key ^= key >> 4; + key *= 0x5052acdb; + key ^= __builtin_bswap32(key); + return key; +} +#endif + +/* + Higher-quality hash function. This is measurably slower in some workloads. +#if __LP64__ + uint32_t ptr_hash(uint64_t key) +{ + key -= __builtin_bswap64(key); + key *= 0x8a970be7488fda55; + key ^= __builtin_bswap64(key); + key *= 0x8a970be7488fda55; + key ^= __builtin_bswap64(key); + return (uint32_t)key; +} +#else +static uint32_t ptr_hash(uint32_t key) +{ + key -= __builtin_bswap32(key); + key *= 0x5052acdb; + key ^= __builtin_bswap32(key); + key *= 0x5052acdb; + key ^= __builtin_bswap32(key); + return key; +} +#endif +*/ + + +// Inlined parts of objc_object's implementation +#include "objc-object.h" #endif /* _OBJC_PRIVATE_H_ */