1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138 |
- #include "objc-private.h"
- #include "objc-abi.h"
- #include <objc/message.h>
- Class object_getClass(id obj)
- {
-
-
-
- if (obj) return obj->getIsa();
- else return Nil;
- }
- Class object_setClass(id obj, Class cls)
- {
- if (!obj) return nil;
-
-
-
-
- if (!cls->isFuture() && !cls->isInitialized()) {
-
-
- lookUpImpOrNil(nil, @selector(initialize), cls, LOOKUP_INITIALIZE);
- }
- return obj->changeIsa(cls);
- }
- BOOL object_isClass(id obj)
- {
- if (!obj) return NO;
- return obj->isClass();
- }
- const char *object_getClassName(id obj)
- {
- return class_getName(obj ? obj->getIsa() : nil);
- }
- IMP object_getMethodImplementation(id obj, SEL name)
- {
- Class cls = (obj ? obj->getIsa() : nil);
- return class_getMethodImplementation(cls, name);
- }
- #if SUPPORT_STRET
- IMP object_getMethodImplementation_stret(id obj, SEL name)
- {
- Class cls = (obj ? obj->getIsa() : nil);
- return class_getMethodImplementation_stret(cls, name);
- }
- #endif
- static bool isScanned(ptrdiff_t ivar_offset, const uint8_t *layout)
- {
- if (!layout) return NO;
- ptrdiff_t index = 0, ivar_index = ivar_offset / sizeof(void*);
- uint8_t byte;
- while ((byte = *layout++)) {
- unsigned skips = (byte >> 4);
- unsigned scans = (byte & 0x0F);
- index += skips;
- if (index > ivar_index) return NO;
- index += scans;
- if (index > ivar_index) return YES;
- }
- return NO;
- }
- static void
- _class_lookUpIvar(Class cls, Ivar ivar, ptrdiff_t& ivarOffset,
- objc_ivar_memory_management_t& memoryManagement)
- {
- ivarOffset = ivar_getOffset(ivar);
-
-
-
-
- bool hasAutomaticIvars = NO;
- for (Class c = cls; c; c = c->superclass) {
- if (c->hasAutomaticIvars()) {
- hasAutomaticIvars = YES;
- break;
- }
- }
- if (hasAutomaticIvars) {
- Class ivarCls = _class_getClassForIvar(cls, ivar);
- if (ivarCls->hasAutomaticIvars()) {
-
-
-
- ptrdiff_t localOffset =
- ivarOffset - ivarCls->alignedInstanceStart();
- if (isScanned(localOffset, class_getIvarLayout(ivarCls))) {
- memoryManagement = objc_ivar_memoryStrong;
- return;
- }
-
- if (isScanned(localOffset, class_getWeakIvarLayout(ivarCls))) {
- memoryManagement = objc_ivar_memoryWeak;
- return;
- }
-
- if (ivarCls->isARC()) {
- memoryManagement = objc_ivar_memoryUnretained;
- return;
- }
- }
- }
-
- memoryManagement = objc_ivar_memoryUnknown;
- }
- objc_ivar_memory_management_t
- _class_getIvarMemoryManagement(Class cls, Ivar ivar)
- {
- ptrdiff_t offset;
- objc_ivar_memory_management_t memoryManagement;
- _class_lookUpIvar(cls, ivar, offset, memoryManagement);
- return memoryManagement;
- }
- static ALWAYS_INLINE
- void _object_setIvar(id obj, Ivar ivar, id value, bool assumeStrong)
- {
- if (!obj || !ivar || obj->isTaggedPointer()) return;
- ptrdiff_t offset;
- objc_ivar_memory_management_t memoryManagement;
- _class_lookUpIvar(obj->ISA(), ivar, offset, memoryManagement);
- if (memoryManagement == objc_ivar_memoryUnknown) {
- if (assumeStrong) memoryManagement = objc_ivar_memoryStrong;
- else memoryManagement = objc_ivar_memoryUnretained;
- }
- id *location = (id *)((char *)obj + offset);
- switch (memoryManagement) {
- case objc_ivar_memoryWeak: objc_storeWeak(location, value); break;
- case objc_ivar_memoryStrong: objc_storeStrong(location, value); break;
- case objc_ivar_memoryUnretained: *location = value; break;
- case objc_ivar_memoryUnknown: _objc_fatal("impossible");
- }
- }
- void object_setIvar(id obj, Ivar ivar, id value)
- {
- return _object_setIvar(obj, ivar, value, false );
- }
- void object_setIvarWithStrongDefault(id obj, Ivar ivar, id value)
- {
- return _object_setIvar(obj, ivar, value, true );
- }
- id object_getIvar(id obj, Ivar ivar)
- {
- if (!obj || !ivar || obj->isTaggedPointer()) return nil;
- ptrdiff_t offset;
- objc_ivar_memory_management_t memoryManagement;
- _class_lookUpIvar(obj->ISA(), ivar, offset, memoryManagement);
- id *location = (id *)((char *)obj + offset);
- if (memoryManagement == objc_ivar_memoryWeak) {
- return objc_loadWeak(location);
- } else {
- return *location;
- }
- }
- static ALWAYS_INLINE
- Ivar _object_setInstanceVariable(id obj, const char *name, void *value,
- bool assumeStrong)
- {
- Ivar ivar = nil;
- if (obj && name && !obj->isTaggedPointer()) {
- if ((ivar = _class_getVariable(obj->ISA(), name))) {
- _object_setIvar(obj, ivar, (id)value, assumeStrong);
- }
- }
- return ivar;
- }
- Ivar object_setInstanceVariable(id obj, const char *name, void *value)
- {
- return _object_setInstanceVariable(obj, name, value, false);
- }
- Ivar object_setInstanceVariableWithStrongDefault(id obj, const char *name,
- void *value)
- {
- return _object_setInstanceVariable(obj, name, value, true);
- }
- Ivar object_getInstanceVariable(id obj, const char *name, void **value)
- {
- if (obj && name && !obj->isTaggedPointer()) {
- Ivar ivar;
- if ((ivar = class_getInstanceVariable(obj->ISA(), name))) {
- if (value) *value = (void *)object_getIvar(obj, ivar);
- return ivar;
- }
- }
- if (value) *value = nil;
- return nil;
- }
- static void object_cxxDestructFromClass(id obj, Class cls)
- {
- void (*dtor)(id);
-
- for ( ; cls; cls = cls->superclass) {
- if (!cls->hasCxxDtor()) return;
- dtor = (void(*)(id))
- lookupMethodInClassAndLoadCache(cls, SEL_cxx_destruct);
- if (dtor != (void(*)(id))_objc_msgForward_impcache) {
- if (PrintCxxCtors) {
- _objc_inform("CXX: calling C++ destructors for class %s",
- cls->nameForLogging());
- }
- (*dtor)(obj);
- }
- }
- }
- void object_cxxDestruct(id obj)
- {
- if (!obj) return;
- if (obj->isTaggedPointer()) return;
- object_cxxDestructFromClass(obj, obj->ISA());
- }
- id
- object_cxxConstructFromClass(id obj, Class cls, int flags)
- {
- ASSERT(cls->hasCxxCtor());
- id (*ctor)(id);
- Class supercls;
- supercls = cls->superclass;
-
- if (supercls && supercls->hasCxxCtor()) {
- bool ok = object_cxxConstructFromClass(obj, supercls, flags);
- if (slowpath(!ok)) return nil;
- }
-
- ctor = (id(*)(id))lookupMethodInClassAndLoadCache(cls, SEL_cxx_construct);
- if (ctor == (id(*)(id))_objc_msgForward_impcache) return obj;
-
-
- if (PrintCxxCtors) {
- _objc_inform("CXX: calling C++ constructors for class %s",
- cls->nameForLogging());
- }
- if (fastpath((*ctor)(obj))) return obj;
- supercls = cls->superclass;
-
-
- if (supercls) object_cxxDestructFromClass(obj, supercls);
- if (flags & OBJECT_CONSTRUCT_FREE_ONFAILURE) free(obj);
- if (flags & OBJECT_CONSTRUCT_CALL_BADALLOC) {
- return _objc_callBadAllocHandler(cls);
- }
- return nil;
- }
- void fixupCopiedIvars(id newObject, id oldObject)
- {
- for (Class cls = oldObject->ISA(); cls; cls = cls->superclass) {
- if (cls->hasAutomaticIvars()) {
-
-
- size_t instanceStart = cls->alignedInstanceStart();
- const uint8_t *strongLayout = class_getIvarLayout(cls);
- if (strongLayout) {
- id *newPtr = (id *)((char*)newObject + instanceStart);
- unsigned char byte;
- while ((byte = *strongLayout++)) {
- unsigned skips = (byte >> 4);
- unsigned scans = (byte & 0x0F);
- newPtr += skips;
- while (scans--) {
-
- id value = *newPtr++;
- if (value) objc_retain(value);
- }
- }
- }
- const uint8_t *weakLayout = class_getWeakIvarLayout(cls);
-
- if (weakLayout) {
- id *newPtr = (id *)((char*)newObject + instanceStart), *oldPtr = (id *)((char*)oldObject + instanceStart);
- unsigned char byte;
- while ((byte = *weakLayout++)) {
- unsigned skips = (byte >> 4);
- unsigned weaks = (byte & 0x0F);
- newPtr += skips, oldPtr += skips;
- while (weaks--) {
- objc_copyWeak(newPtr, oldPtr);
- ++newPtr, ++oldPtr;
- }
- }
- }
- }
- }
- }
- Method class_getClassMethod(Class cls, SEL sel)
- {
- if (!cls || !sel) return nil;
- return class_getInstanceMethod(cls->getMeta(), sel);
- }
- Ivar class_getInstanceVariable(Class cls, const char *name)
- {
- if (!cls || !name) return nil;
- return _class_getVariable(cls, name);
- }
- Ivar class_getClassVariable(Class cls, const char *name)
- {
- if (!cls) return nil;
- return class_getInstanceVariable(cls->ISA(), name);
- }
- BREAKPOINT_FUNCTION(
- void gdb_objc_class_changed(Class cls, unsigned long changes, const char *classname)
- );
- BOOL class_respondsToMethod(Class cls, SEL sel)
- {
- OBJC_WARN_DEPRECATED;
- return class_respondsToSelector(cls, sel);
- }
- BOOL class_respondsToSelector(Class cls, SEL sel)
- {
- return class_respondsToSelector_inst(nil, sel, cls);
- }
- NEVER_INLINE BOOL
- class_respondsToSelector_inst(id inst, SEL sel, Class cls)
- {
-
-
- return sel && cls && lookUpImpOrNil(inst, sel, cls, LOOKUP_RESOLVER);
- }
- IMP class_lookupMethod(Class cls, SEL sel)
- {
- OBJC_WARN_DEPRECATED;
-
- if (!sel) {
- __objc_error(cls, "invalid selector (null)");
- }
- return class_getMethodImplementation(cls, sel);
- }
- IMP class_getMethodImplementation(Class cls, SEL sel)
- {
- IMP imp;
- if (!cls || !sel) return nil;
- imp = lookUpImpOrNil(nil, sel, cls, LOOKUP_INITIALIZE | LOOKUP_RESOLVER);
-
- if (!imp) {
- return _objc_msgForward;
- }
- return imp;
- }
- #if SUPPORT_STRET
- IMP class_getMethodImplementation_stret(Class cls, SEL sel)
- {
- IMP imp = class_getMethodImplementation(cls, sel);
-
- if (imp == (IMP)&_objc_msgForward ) {
- return (IMP)&_objc_msgForward_stret;
- }
- return imp;
- }
- #endif
- spinlock_t objcMsgLogLock;
- #if !SUPPORT_MESSAGE_LOGGING
- void instrumentObjcMessageSends(BOOL flag)
- {
- }
- #else
- bool objcMsgLogEnabled = false;
- static int objcMsgLogFD = -1;
- bool logMessageSend(bool isClassMethod,
- const char *objectsClass,
- const char *implementingClass,
- SEL selector)
- {
- char buf[ 1024 ];
-
- if (objcMsgLogFD == (-1))
- {
- snprintf (buf, sizeof(buf), "/tmp/msgSends-%d", (int) getpid ());
- objcMsgLogFD = secure_open (buf, O_WRONLY | O_CREAT, geteuid());
- if (objcMsgLogFD < 0) {
-
- objcMsgLogEnabled = false;
- objcMsgLogFD = -1;
- return true;
- }
- }
-
- snprintf(buf, sizeof(buf), "%c %s %s %s\n",
- isClassMethod ? '+' : '-',
- objectsClass,
- implementingClass,
- sel_getName(selector));
- objcMsgLogLock.lock();
- write (objcMsgLogFD, buf, strlen(buf));
- objcMsgLogLock.unlock();
-
- return false;
- }
- void instrumentObjcMessageSends(BOOL flag)
- {
- bool enable = flag;
-
- if (objcMsgLogEnabled == enable)
- return;
-
- if (enable)
- _objc_flush_caches(Nil);
-
- if (objcMsgLogFD != -1)
- fsync (objcMsgLogFD);
- objcMsgLogEnabled = enable;
- }
- #endif
- Class _calloc_class(size_t size)
- {
- return (Class) calloc(1, size);
- }
- Class class_getSuperclass(Class cls)
- {
- if (!cls) return nil;
- return cls->superclass;
- }
- BOOL class_isMetaClass(Class cls)
- {
- if (!cls) return NO;
- return cls->isMetaClass();
- }
- size_t class_getInstanceSize(Class cls)
- {
- if (!cls) return 0;
- return cls->alignedInstanceSize();
- }
- unsigned int method_getNumberOfArguments(Method m)
- {
- if (!m) return 0;
- return encoding_getNumberOfArguments(method_getTypeEncoding(m));
- }
- void method_getReturnType(Method m, char *dst, size_t dst_len)
- {
- encoding_getReturnType(method_getTypeEncoding(m), dst, dst_len);
- }
- char * method_copyReturnType(Method m)
- {
- return encoding_copyReturnType(method_getTypeEncoding(m));
- }
- void method_getArgumentType(Method m, unsigned int index,
- char *dst, size_t dst_len)
- {
- encoding_getArgumentType(method_getTypeEncoding(m),
- index, dst, dst_len);
- }
- char * method_copyArgumentType(Method m, unsigned int index)
- {
- return encoding_copyArgumentType(method_getTypeEncoding(m), index);
- }
- unsigned
- _class_createInstancesFromZone(Class cls, size_t extraBytes, void *zone,
- id *results, unsigned num_requested)
- {
- unsigned num_allocated;
- if (!cls) return 0;
- size_t size = cls->instanceSize(extraBytes);
- num_allocated =
- malloc_zone_batch_malloc((malloc_zone_t *)(zone ? zone : malloc_default_zone()),
- size, (void**)results, num_requested);
- for (unsigned i = 0; i < num_allocated; i++) {
- bzero(results[i], size);
- }
-
- unsigned shift = 0;
- bool ctor = cls->hasCxxCtor();
- for (unsigned i = 0; i < num_allocated; i++) {
- id obj = results[i];
- obj->initIsa(cls);
- if (ctor) {
- obj = object_cxxConstructFromClass(obj, cls,
- OBJECT_CONSTRUCT_FREE_ONFAILURE);
- }
- if (obj) {
- results[i-shift] = obj;
- } else {
- shift++;
- }
- }
- return num_allocated - shift;
- }
- void
- inform_duplicate(const char *name, Class oldCls, Class newCls)
- {
- #if TARGET_OS_WIN32
- (DebugDuplicateClasses ? _objc_fatal : _objc_inform)
- ("Class %s is implemented in two different images.", name);
- #else
- const header_info *oldHeader = _headerForClass(oldCls);
- const header_info *newHeader = _headerForClass(newCls);
- const char *oldName = oldHeader ? oldHeader->fname() : "??";
- const char *newName = newHeader ? newHeader->fname() : "??";
- (DebugDuplicateClasses ? _objc_fatal : _objc_inform)
- ("Class %s is implemented in both %s (%p) and %s (%p). "
- "One of the two will be used. Which one is undefined.",
- name, oldName, oldCls, newName, newCls);
- #endif
- }
- const char *
- copyPropertyAttributeString(const objc_property_attribute_t *attrs,
- unsigned int count)
- {
- char *result;
- unsigned int i;
- if (count == 0) return strdup("");
-
- #if DEBUG
-
- for (i = 0; i < count; i++) {
- ASSERT(attrs[i].name);
- ASSERT(strlen(attrs[i].name) > 0);
- ASSERT(! strchr(attrs[i].name, ','));
- ASSERT(! strchr(attrs[i].name, '"'));
- if (attrs[i].value) ASSERT(! strchr(attrs[i].value, ','));
- }
- #endif
- size_t len = 0;
- for (i = 0; i < count; i++) {
- if (attrs[i].value) {
- size_t namelen = strlen(attrs[i].name);
- if (namelen > 1) namelen += 2;
- len += namelen + strlen(attrs[i].value) + 1;
- }
- }
- result = (char *)malloc(len + 1);
- char *s = result;
- for (i = 0; i < count; i++) {
- if (attrs[i].value) {
- size_t namelen = strlen(attrs[i].name);
- if (namelen > 1) {
- s += sprintf(s, "\"%s\"%s,", attrs[i].name, attrs[i].value);
- } else {
- s += sprintf(s, "%s%s,", attrs[i].name, attrs[i].value);
- }
- }
- }
-
- if (s > result) s[-1] = '\0';
- return result;
- }
- static unsigned int
- iteratePropertyAttributes(const char *attrs,
- bool (*fn)(unsigned int index,
- void *ctx1, void *ctx2,
- const char *name, size_t nlen,
- const char *value, size_t vlen),
- void *ctx1, void *ctx2)
- {
- if (!attrs) return 0;
- #if DEBUG
- const char *attrsend = attrs + strlen(attrs);
- #endif
- unsigned int attrcount = 0;
- while (*attrs) {
-
- const char *start = attrs;
- const char *end = start + strcspn(attrs, ",");
-
- attrs = *end ? end+1 : end;
- assert(attrs <= attrsend);
- assert(start <= attrsend);
- assert(end <= attrsend);
-
-
- if (start == end) continue;
-
- const char *nameStart;
- const char *nameEnd;
- ASSERT(start < end);
- ASSERT(*start);
- if (*start != '\"') {
-
- nameStart = start;
- nameEnd = start+1;
- start++;
- }
- else {
-
- nameStart = start+1;
- nameEnd = nameStart + strcspn(nameStart, "\",");
- start++;
- start += nameEnd - nameStart;
- if (*start == '\"') start++;
- }
-
- const char *valueStart;
- const char *valueEnd;
- ASSERT(start <= end);
- valueStart = start;
- valueEnd = end;
- bool more = (*fn)(attrcount, ctx1, ctx2,
- nameStart, nameEnd-nameStart,
- valueStart, valueEnd-valueStart);
- attrcount++;
- if (!more) break;
- }
- return attrcount;
- }
- static bool
- copyOneAttribute(unsigned int index, void *ctxa, void *ctxs,
- const char *name, size_t nlen, const char *value, size_t vlen)
- {
- objc_property_attribute_t **ap = (objc_property_attribute_t**)ctxa;
- char **sp = (char **)ctxs;
- objc_property_attribute_t *a = *ap;
- char *s = *sp;
- a->name = s;
- memcpy(s, name, nlen);
- s += nlen;
- *s++ = '\0';
-
- a->value = s;
- memcpy(s, value, vlen);
- s += vlen;
- *s++ = '\0';
- a++;
-
- *ap = a;
- *sp = s;
- return YES;
- }
-
- objc_property_attribute_t *
- copyPropertyAttributeList(const char *attrs, unsigned int *outCount)
- {
- if (!attrs) {
- if (outCount) *outCount = 0;
- return nil;
- }
-
-
-
-
-
- unsigned int attrcount = 1;
- const char *s;
- for (s = attrs; s && *s; s++) {
- if (*s == ',') attrcount++;
- }
- size_t size =
- attrcount * sizeof(objc_property_attribute_t) +
- sizeof(objc_property_attribute_t) +
- strlen(attrs) +
- attrcount * 2;
- objc_property_attribute_t *result = (objc_property_attribute_t *)
- calloc(size, 1);
- objc_property_attribute_t *ra = result;
- char *rs = (char *)(ra+attrcount+1);
- attrcount = iteratePropertyAttributes(attrs, copyOneAttribute, &ra, &rs);
- ASSERT((uint8_t *)(ra+1) <= (uint8_t *)result+size);
- ASSERT((uint8_t *)rs <= (uint8_t *)result+size);
- if (attrcount == 0) {
- free(result);
- result = nil;
- }
- if (outCount) *outCount = attrcount;
- return result;
- }
- static bool
- findOneAttribute(unsigned int index, void *ctxa, void *ctxs,
- const char *name, size_t nlen, const char *value, size_t vlen)
- {
- const char *query = (char *)ctxa;
- char **resultp = (char **)ctxs;
- if (strlen(query) == nlen && 0 == strncmp(name, query, nlen)) {
- char *result = (char *)calloc(vlen+1, 1);
- memcpy(result, value, vlen);
- result[vlen] = '\0';
- *resultp = result;
- return NO;
- }
- return YES;
- }
- char *copyPropertyAttributeValue(const char *attrs, const char *name)
- {
- char *result = nil;
- iteratePropertyAttributes(attrs, findOneAttribute, (void*)name, &result);
- return result;
- }
|