// Note that test ARCLayoutsWithoutWeak uses the same files
// with different build options.
/*
TEST_CONFIG MEM=arc
TEST_BUILD
mkdir -p $T{OBJDIR}
$C{COMPILE_NOLINK_NOMEM} -c $DIR/MRCBase.m -o $T{OBJDIR}/MRCBase.o
$C{COMPILE_NOLINK_NOMEM} -c $DIR/MRCARC.m -o $T{OBJDIR}/MRCARC.o
$C{COMPILE_NOLINK} -c $DIR/ARCBase.m -o $T{OBJDIR}/ARCBase.o
$C{COMPILE_NOLINK} -c $DIR/ARCMRC.m -o $T{OBJDIR}/ARCMRC.o
$C{COMPILE} '-DNAME=\"ARCLayouts.m\"' -fobjc-arc $DIR/ARCLayouts.m -x none $T{OBJDIR}/MRCBase.o $T{OBJDIR}/MRCARC.o $T{OBJDIR}/ARCBase.o $T{OBJDIR}/ARCMRC.o -framework Foundation -o ARCLayouts.exe
END
*/
#include "test.h"
#import <stdio.h>
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import "ARCMRC.h"
#import "MRCARC.h"
@interface NSObject (Layouts)
+ (const char *)strongLayout;
+ (const char *)weakLayout;
@end
void printlayout(const char *name, const uint8_t *layout)
{
if (!testverbose()) return;
testprintf("
// these use fprintf() to avoid repeated VERBOSE: in the middle of the line
if (!layout) {
fprintf(stderr, "NULL\n");
return;
}
const uint8_t *c;
for (c = layout; *c; c++) {
fprintf(stderr, " }
fprintf(stderr, "00\n");
}
@implementation NSObject (Layouts)
+ (const char *)strongLayout {
const uint8_t *layout = class_getIvarLayout(self);
printlayout("strong", layout);
return (const char *)layout;
}
+ (const char *)weakLayout {
const uint8_t *weakLayout = class_getWeakIvarLayout(self);
printlayout("weak", weakLayout);
return (const char *)weakLayout;
}
+ (Ivar)instanceVariable:(const char *)name {
return class_getInstanceVariable(self, name);
}
@end
void checkMM(Class cls, const char *ivarName,
objc_ivar_memory_management_t mmExpected)
{
Ivar ivar = [cls instanceVariable:ivarName];
objc_ivar_memory_management_t mm = _class_getIvarMemoryManagement(cls,ivar);
testprintf(" class_getName(cls), ivarName, mmExpected, mm);
testassert(mmExpected == mm);
}
int main (int argc __unused, const char * argv[] __unused) {
testprintf("ARCMRC\n");
testassert(strcmp([ARCMRC strongLayout], "\x01") == 0);
testassert([ARCMRC weakLayout] == NULL);
// Verify that ARCBase->misalign and MRCBase->alignment did their thing.
testassert(ivar_getOffset(class_getInstanceVariable([ARCBase class], "misalign2")) & 1);
testassert(ivar_getOffset(class_getInstanceVariable([MRCBase class], "alignment")) > (ptrdiff_t)sizeof(void*));
testprintf("ARCMisalign\n");
testassert([ARCMisalign strongLayout] == NULL);
testassert([ARCMisalign weakLayout] == NULL);
testprintf("ARCBase\n");
if (strcmp([ARCBase strongLayout], "\x11\x30") == 0) {
testwarn("1130 layout is a compiler flaw but doesn't fail");
} else {
testassert(strcmp([ARCBase strongLayout], "\x11") == 0);
}
testassert(strcmp([ARCBase weakLayout], "\x31") == 0);
testprintf("MRCARC\n");
testassert([MRCARC strongLayout] == NULL);
testassert([MRCARC weakLayout] == NULL);
testprintf("MRCBase\n");
// MRC marks __weak only.
testassert([MRCBase strongLayout] == NULL);
if (supportsMRCWeak) {
testassert(strcmp([MRCBase weakLayout], "\x71") == 0);
} else {
testassert([MRCBase weakLayout] == nil);
}
// now check consistency between dynamic accessors and KVC, etc.
ARCMRC *am = [ARCMRC new];
MRCARC *ma = [MRCARC new];
NSString *amValue = [[NSString alloc] initWithFormat:@" NSString *amValue2 = [[NSString alloc] initWithFormat:@" NSString *maValue = [[NSString alloc] initWithFormat:@" NSString *maValue2 = [[NSString alloc] initWithFormat:@"
am.number = M_PI;
object_setIvar(am, [ARCMRC instanceVariable:"object"], amValue);
testassert(CFGetRetainCount((__bridge CFTypeRef)amValue) == 1);
testassert(am.object == amValue);
object_setIvarWithStrongDefault(am, [ARCMRC instanceVariable:"object"], amValue2);
testassert(CFGetRetainCount((__bridge CFTypeRef)amValue2) == 2);
testassert(am.object == amValue2);
am.pointer = @selector(ARCMRC);
object_setIvar(am, [ARCMRC instanceVariable:"delegate"], ma);
testassert(CFGetRetainCount((__bridge CFTypeRef)ma) == 1);
testassert(am.delegate == ma);
object_setIvarWithStrongDefault(am, [ARCMRC instanceVariable:"delegate"], ma);
testassert(CFGetRetainCount((__bridge CFTypeRef)ma) == 1);
testassert(am.delegate == ma);
ma.number = M_E;
object_setIvar(ma, [MRCARC instanceVariable:"object"], maValue);
testassert(CFGetRetainCount((__bridge CFTypeRef)maValue) == 2);
@autoreleasepool {
testassert(ma.object == maValue);
}
object_setIvarWithStrongDefault(ma, [MRCARC instanceVariable:"object"], maValue2);
testassert(CFGetRetainCount((__bridge CFTypeRef)maValue2) == 2);
@autoreleasepool {
testassert(ma.object == maValue2);
}
ma.pointer = @selector(MRCARC);
ma.delegate = am;
object_setIvar(ma, [MRCARC instanceVariable:"delegate"], am);
testassert(CFGetRetainCount((__bridge CFTypeRef)am) == 1);
@autoreleasepool {
testassert(ma.delegate == am);
}
object_setIvarWithStrongDefault(ma, [MRCARC instanceVariable:"delegate"], am);
testassert(CFGetRetainCount((__bridge CFTypeRef)am) == 1);
@autoreleasepool {
testassert(ma.delegate == am);
}
// Verify that object_copy() handles ARC variables correctly.
MRCARC *ma2 = docopy(ma);
testassert(ma2);
testassert(ma2 != ma);
testassert(CFGetRetainCount((__bridge CFTypeRef)maValue2) == 3);
testassert(CFGetRetainCount((__bridge CFTypeRef)am) == 1);
testassert(ma2.number == ma.number);
testassert(ma2.object == ma.object);
@autoreleasepool {
testassert(ma2.delegate == ma.delegate);
}
testassert(ma2.pointer == ma.pointer);
// Test _class_getIvarMemoryManagement() SPI
objc_ivar_memory_management_t memoryMRCWeak =
supportsMRCWeak ? objc_ivar_memoryWeak : objc_ivar_memoryUnknown;
checkMM([ARCMRC class], "number", objc_ivar_memoryUnknown);
checkMM([ARCMRC class], "object", objc_ivar_memoryUnknown);
checkMM([ARCMRC class], "pointer", objc_ivar_memoryUnknown);
checkMM([ARCMRC class], "delegate", memoryMRCWeak);
checkMM([ARCMRC class], "dataSource", objc_ivar_memoryStrong);
checkMM([MRCARC class], "number", objc_ivar_memoryUnretained);
checkMM([MRCARC class], "object", objc_ivar_memoryStrong);
checkMM([MRCARC class], "pointer", objc_ivar_memoryUnretained);
checkMM([MRCARC class], "delegate", objc_ivar_memoryWeak);
checkMM([MRCARC class], "dataSource", objc_ivar_memoryUnknown);
checkMM([ARCBase class], "number", objc_ivar_memoryUnretained);
checkMM([ARCBase class], "object", objc_ivar_memoryStrong);
checkMM([ARCBase class], "pointer", objc_ivar_memoryUnretained);
checkMM([ARCBase class], "delegate", objc_ivar_memoryWeak);
checkMM([MRCBase class], "number", objc_ivar_memoryUnknown);
checkMM([MRCBase class], "object", objc_ivar_memoryUnknown);
checkMM([MRCBase class], "pointer", objc_ivar_memoryUnknown);
checkMM([MRCBase class], "delegate", memoryMRCWeak);
succeed(NAME);
return 0;
}