123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499 |
- /*
- TEST_BUILD
- $C{COMPILE} -fobjc-weak $DIR/ivarSlide1.m $DIR/ivarSlide.m -o ivarSlide.exe
- END
- */
- #include "test.h"
- #include <string.h>
- #include <stdint.h>
- #include <objc/objc-runtime.h>
- #include <objc/objc-auto.h>
- // fixme should check ARC layout handling
- // current test checks GC layout handling which is dead
- #define FIXME_CHECK_ARC_LAYOUTS 0
- // ARC doesn't like __strong void* or __weak void*
- #define gc_weak
- #define gc_strong
- #define OLD 1
- #include "ivarSlide.h"
- #define ustrcmp(a, b) strcmp((char *)a, (char *)b)
- #ifdef __cplusplus
- class CXX {
- public:
- static uintptr_t count;
- uintptr_t magic;
- CXX() : magic(1) { }
- ~CXX() { count += magic; }
- };
- uintptr_t CXX::count;
- #endif
- @interface Bitfields : Super {
- uint8_t uint8_ivar;
- uint8_t uint8_bitfield1 :7;
- uint8_t uint8_bitfield2 :1;
- id id_ivar;
-
- uintptr_t uintptr_ivar;
- uintptr_t /*uintptr_bitfield1*/ :31; // anonymous (rdar://5723893)
- uintptr_t uintptr_bitfield2 :1;
- id id_ivar2;
- }
- @end
- @implementation Bitfields @end
- @interface Sub : Super {
- @public
- uintptr_t subIvar;
- gc_strong void* subIvar2;
- gc_weak void* subIvar3;
- #ifdef __cplusplus
- CXX cxx;
- #else
- // same layout as cxx
- uintptr_t cxx_magic;
- #endif
- }
- @end
- @implementation Sub @end
- @interface Sub2 : ShrinkingSuper {
- @public
- gc_weak void* subIvar;
- gc_strong void* subIvar2;
- }
- @end
- @implementation Sub2 @end
- @interface MoreStrongSub : MoreStrongSuper { id subIvar; } @end
- @interface LessStrongSub : LessStrongSuper { id subIvar; } @end
- @interface MoreWeakSub : MoreWeakSuper { id subIvar; } @end
- @interface MoreWeak2Sub : MoreWeak2Super { id subIvar; } @end
- @interface LessWeakSub : LessWeakSuper { id subIvar; } @end
- @interface LessWeak2Sub : LessWeak2Super { id subIvar; } @end
- @implementation MoreStrongSub @end
- @implementation LessStrongSub @end
- @implementation MoreWeakSub @end
- @implementation MoreWeak2Sub @end
- @implementation LessWeakSub @end
- @implementation LessWeak2Sub @end
- @interface NoGCChangeSub : NoGCChangeSuper {
- @public
- char subc3;
- }
- @end
- @implementation NoGCChangeSub @end
- @interface RunsOf15Sub : RunsOf15 {
- @public
- char sub;
- }
- @end
- @implementation RunsOf15Sub @end
- int main(int argc __attribute__((unused)), char **argv)
- {
- #if __has_feature(objc_arc)
- testwarn("fixme check ARC layouts too");
- #endif
- /*
- Bitfield ivars.
- rdar://5723893 anonymous bitfield ivars crash when slid
- rdar://5724385 bitfield ivar alignment incorrect
- Compile-time layout of Bitfields:
- [0 scan] isa
- [1 skip] uint8_ivar, uint8_bitfield
- [2 scan] id_ivar
- [3 skip] uintptr_ivar
- [4 skip] uintptr_bitfield
- [5 scan] id_ivar2
- Runtime layout of Bitfields:
- [0 scan] isa
- [1 skip] superIvar
- [2 skip] uint8_ivar, uint8_bitfield
- [3 scan] id_ivar
- [4 skip] uintptr_ivar
- [5 skip] uintptr_bitfield
- [6 scan] id_ivar2
- */
- [Bitfields class];
- testassert(class_getInstanceSize([Bitfields class]) == 7*sizeof(void*));
- if (FIXME_CHECK_ARC_LAYOUTS) {
- const uint8_t *bitfieldlayout;
- bitfieldlayout = class_getIvarLayout([Bitfields class]);
- testassert(0 == ustrcmp(bitfieldlayout, "\x01\x21\x21"));
- bitfieldlayout = class_getWeakIvarLayout([Bitfields class]);
- testassert(bitfieldlayout == NULL);
- }
- /*
- Compile-time layout of Sub:
- [0 scan] isa
- [1 skip] subIvar
- [2 scan] subIvar2
- [3 weak] subIvar3
- [6 skip] cxx
- Runtime layout of Sub:
- [0 scan] isa
- [1 skip] superIvar
- [2 skip] subIvar
- [3 scan] subIvar2
- [4 weak] subIvar3
- [6 skip] cxx
- Also, superIvar is only one byte, so subIvar's alignment must
- be handled correctly.
- fixme test more layouts
- */
- Ivar ivar;
- static Sub * volatile sub;
- sub = [Sub new];
- sub->subIvar = 10;
- uintptr_t *subwords = (uintptr_t *)(__bridge void*)sub;
- testassert(subwords[2] == 10);
- #ifdef __cplusplus
- testassert(subwords[5] == 1);
- testassert(sub->cxx.magic == 1);
- sub->cxx.magic++;
- testassert(subwords[5] == 2);
- testassert(sub->cxx.magic == 2);
- # if __has_feature(objc_arc)
- sub = nil;
- # else
- [sub dealloc];
- # endif
- testassert(CXX::count == 2);
- #endif
- testassert(class_getInstanceSize([Sub class]) == 6*sizeof(void*));
- ivar = class_getInstanceVariable([Sub class], "subIvar");
- testassert(ivar);
- testassert(2*sizeof(void*) == (size_t)ivar_getOffset(ivar));
- testassert(0 == strcmp(ivar_getName(ivar), "subIvar"));
- testassert(0 == strcmp(ivar_getTypeEncoding(ivar),
- #if __LP64__
- "Q"
- #else
- "L"
- #endif
- ));
- #ifdef __cplusplus
- ivar = class_getInstanceVariable([Sub class], "cxx");
- testassert(ivar);
- #endif
- ivar = class_getInstanceVariable([Super class], "superIvar");
- testassert(ivar);
- testassert(sizeof(void*) == (size_t)ivar_getOffset(ivar));
- testassert(0 == strcmp(ivar_getName(ivar), "superIvar"));
- testassert(0 == strcmp(ivar_getTypeEncoding(ivar), "c"));
- ivar = class_getInstanceVariable([Super class], "subIvar");
- testassert(!ivar);
- if (FIXME_CHECK_ARC_LAYOUTS) {
- const uint8_t *superlayout;
- const uint8_t *sublayout;
- superlayout = class_getIvarLayout([Super class]);
- sublayout = class_getIvarLayout([Sub class]);
- testassert(0 == ustrcmp(superlayout, "\x01\x10"));
- testassert(0 == ustrcmp(sublayout, "\x01\x21\x20"));
- superlayout = class_getWeakIvarLayout([Super class]);
- sublayout = class_getWeakIvarLayout([Sub class]);
- testassert(superlayout == NULL);
- testassert(0 == ustrcmp(sublayout, "\x41\x10"));
- }
- /*
- Shrinking superclass.
- Subclass ivars do not compact, but the GC layout needs to
- update, including the gap that the superclass no longer spans.
- Compile-time layout of Sub2:
- [0 scan] isa
- [1-5 scan] superIvar
- [6-10 weak] superIvar2
- [11 weak] subIvar
- [12 scan] subIvar2
- Runtime layout of Sub2:
- [0 scan] isa
- [1-10 skip] was superIvar
- [11 weak] subIvar
- [12 scan] subIvar2
- */
- Sub2 *sub2 = [Sub2 new];
- uintptr_t *sub2words = (uintptr_t *)(__bridge void*)sub2;
- sub2->subIvar = (void *)10;
- testassert(sub2words[11] == 10);
- testassert(class_getInstanceSize([Sub2 class]) == 13*sizeof(void*));
- ivar = class_getInstanceVariable([Sub2 class], "subIvar");
- testassert(ivar);
- testassert(11*sizeof(void*) == (size_t)ivar_getOffset(ivar));
- testassert(0 == strcmp(ivar_getName(ivar), "subIvar"));
- ivar = class_getInstanceVariable([ShrinkingSuper class], "superIvar");
- testassert(!ivar);
- if (FIXME_CHECK_ARC_LAYOUTS) {
- const uint8_t *superlayout;
- const uint8_t *sublayout;
- superlayout = class_getIvarLayout([ShrinkingSuper class]);
- sublayout = class_getIvarLayout([Sub2 class]);
- // only `isa` is left; superIvar[] and superIvar2[] are gone
- testassert(superlayout == NULL || 0 == ustrcmp(superlayout, "\x01"));
- testassert(0 == ustrcmp(sublayout, "\x01\xb1"));
- superlayout = class_getWeakIvarLayout([ShrinkingSuper class]);
- sublayout = class_getWeakIvarLayout([Sub2 class]);
- testassert(superlayout == NULL);
- testassert(0 == ustrcmp(sublayout, "\xb1\x10"));
- }
- /*
- Ivars slide but GC layouts stay the same
- Here, the last word of the superclass is misaligned, but
- its GC layout includes a bit for that whole word.
- Additionally, all of the subclass ivars fit into that word too,
- both before and after sliding.
- The runtime will try to slide the GC layout and must not be
- confused (rdar://6851700). Note that the second skip-word may or may
- not actually be included, because it crosses the end of the object.
-
- Compile-time layout of NoGCChangeSub:
- [0 scan] isa
- [1 skip] d
- [2 skip] superc1, subc3
- Runtime layout of NoGCChangeSub:
- [0 scan] isa
- [1 skip] d
- [2 skip] superc1, superc2, subc3
- */
- if (FIXME_CHECK_ARC_LAYOUTS) {
- Ivar ivar1 = class_getInstanceVariable([NoGCChangeSub class], "superc1");
- testassert(ivar1);
- Ivar ivar2 = class_getInstanceVariable([NoGCChangeSub class], "superc2");
- testassert(ivar2);
- Ivar ivar3 = class_getInstanceVariable([NoGCChangeSub class], "subc3");
- testassert(ivar3);
- testassert(ivar_getOffset(ivar1) != ivar_getOffset(ivar2) &&
- ivar_getOffset(ivar1) != ivar_getOffset(ivar3) &&
- ivar_getOffset(ivar2) != ivar_getOffset(ivar3));
- }
- /* Ivar layout includes runs of 15 words.
- rdar://6859875 this would generate a truncated GC layout.
- */
- if (FIXME_CHECK_ARC_LAYOUTS) {
- const uint8_t *layout =
- class_getIvarLayout(objc_getClass("RunsOf15Sub"));
- testassert(layout);
- int totalSkip = 0;
- int totalScan = 0;
- // should find 30+ each of skip and scan
- uint8_t c;
- while ((c = *layout++)) {
- totalSkip += c>>4;
- totalScan += c&0xf;
- }
- testassert(totalSkip >= 30);
- testassert(totalScan >= 30);
- }
- /*
- Non-strong -> strong
- Classes do not change size, but GC layouts must be updated.
- Both new and old ABI detect this case (rdar://5774578)
- Compile-time layout of MoreStrongSub:
- [0 scan] isa
- [1 skip] superIvar
- [2 scan] subIvar
- Runtime layout of MoreStrongSub:
- [0 scan] isa
- [1 scan] superIvar
- [2 scan] subIvar
- */
- testassert(class_getInstanceSize([MoreStrongSub class]) == 3*sizeof(void*));
- if (FIXME_CHECK_ARC_LAYOUTS) {
- const uint8_t *layout;
- layout = class_getIvarLayout([MoreStrongSub class]);
- testassert(layout == NULL);
- layout = class_getWeakIvarLayout([MoreStrongSub class]);
- testassert(layout == NULL);
- }
- /*
- Strong -> weak
- Classes do not change size, but GC layouts must be updated.
- Old ABI intentionally does not detect this case (rdar://5774578)
-
- Compile-time layout of MoreWeakSub:
- [0 scan] isa
- [1 scan] superIvar
- [2 scan] subIvar
- Runtime layout of MoreWeakSub:
- [0 scan] isa
- [1 weak] superIvar
- [2 scan] subIvar
- */
- testassert(class_getInstanceSize([MoreWeakSub class]) == 3*sizeof(void*));
- if (FIXME_CHECK_ARC_LAYOUTS) {
- const uint8_t *layout;
- layout = class_getIvarLayout([MoreWeakSub class]);
- testassert(0 == ustrcmp(layout, "\x01\x11"));
- layout = class_getWeakIvarLayout([MoreWeakSub class]);
- testassert(0 == ustrcmp(layout, "\x11\x10"));
- }
- /*
- Non-strong -> weak
- Classes do not change size, but GC layouts must be updated.
- Old ABI intentionally does not detect this case (rdar://5774578)
-
- Compile-time layout of MoreWeak2Sub:
- [0 scan] isa
- [1 skip] superIvar
- [2 scan] subIvar
- Runtime layout of MoreWeak2Sub:
- [0 scan] isa
- [1 weak] superIvar
- [2 scan] subIvar
- */
- testassert(class_getInstanceSize([MoreWeak2Sub class]) == 3*sizeof(void*));
- if (FIXME_CHECK_ARC_LAYOUTS) {
- const uint8_t *layout;
- layout = class_getIvarLayout([MoreWeak2Sub class]);
- testassert(0 == ustrcmp(layout, "\x01\x11") ||
- 0 == ustrcmp(layout, "\x01\x10\x01"));
- layout = class_getWeakIvarLayout([MoreWeak2Sub class]);
- testassert(0 == ustrcmp(layout, "\x11\x10"));
- }
- /*
- Strong -> non-strong
- Classes do not change size, but GC layouts must be updated.
- Old ABI intentionally does not detect this case (rdar://5774578)
- Compile-time layout of LessStrongSub:
- [0 scan] isa
- [1 scan] superIvar
- [2 scan] subIvar
- Runtime layout of LessStrongSub:
- [0 scan] isa
- [1 skip] superIvar
- [2 scan] subIvar
- */
- testassert(class_getInstanceSize([LessStrongSub class]) == 3*sizeof(void*));
- if (FIXME_CHECK_ARC_LAYOUTS) {
- const uint8_t *layout;
- layout = class_getIvarLayout([LessStrongSub class]);
- testassert(0 == ustrcmp(layout, "\x01\x11"));
- layout = class_getWeakIvarLayout([LessStrongSub class]);
- testassert(layout == NULL);
- }
- /*
- Weak -> strong
- Classes do not change size, but GC layouts must be updated.
- Both new and old ABI detect this case (rdar://5774578 rdar://6924114)
-
- Compile-time layout of LessWeakSub:
- [0 scan] isa
- [1 weak] superIvar
- [2 scan] subIvar
- Runtime layout of LessWeakSub:
- [0 scan] isa
- [1 scan] superIvar
- [2 scan] subIvar
- */
- testassert(class_getInstanceSize([LessWeakSub class]) == 3*sizeof(void*));
- if (FIXME_CHECK_ARC_LAYOUTS) {
- const uint8_t *layout;
- layout = class_getIvarLayout([LessWeakSub class]);
- testassert(layout == NULL);
- layout = class_getWeakIvarLayout([LessWeakSub class]);
- testassert(layout == NULL);
- }
- /*
- Weak -> non-strong
- Classes do not change size, but GC layouts must be updated.
- Old ABI intentionally does not detect this case (rdar://5774578)
-
- Compile-time layout of LessWeak2Sub:
- [0 scan] isa
- [1 weak] superIvar
- [2 scan] subIvar
- Runtime layout of LessWeak2Sub:
- [0 scan] isa
- [1 skip] superIvar
- [2 scan] subIvar
- */
- testassert(class_getInstanceSize([LessWeak2Sub class]) == 3*sizeof(void*));
- if (FIXME_CHECK_ARC_LAYOUTS) {
- const uint8_t *layout;
- layout = class_getIvarLayout([LessWeak2Sub class]);
- testassert(0 == ustrcmp(layout, "\x01\x11") ||
- 0 == ustrcmp(layout, "\x01\x10\x01"));
- layout = class_getWeakIvarLayout([LessWeak2Sub class]);
- testassert(layout == NULL);
- }
- succeed(basename(argv[0]));
- return 0;
- }
|