3 $C{COMPILE} $DIR/ivarSlide1.m $DIR/ivarSlide.m -o ivarSlide.out
10 #include <objc/objc-runtime.h>
11 #include <objc/objc-auto.h>
13 // ARC doesn't like __strong void* or __weak void*
15 # define gc_weak __weak
16 # define gc_strong __strong
23 #include "ivarSlide.h"
25 #define ustrcmp(a, b) strcmp((char *)a, (char *)b)
30 static uintptr_t count;
33 ~CXX() { count += magic; }
38 @interface Bitfields : Super {
40 uint8_t uint8_bitfield1 :7;
41 uint8_t uint8_bitfield2 :1;
45 uintptr_t uintptr_ivar;
46 uintptr_t /*uintptr_bitfield1*/ :31; // anonymous (rdar://5723893)
47 uintptr_t uintptr_bitfield2 :1;
53 @implementation Bitfields @end
56 @interface Sub : Super {
59 gc_strong void* subIvar2;
60 gc_weak void* subIvar3;
70 @implementation Sub @end
73 @interface Sub2 : ShrinkingSuper {
75 gc_weak void* subIvar;
76 gc_strong void* subIvar2;
80 @implementation Sub2 @end
82 @interface MoreStrongSub : MoreStrongSuper { id subIvar; } @end
83 @interface LessStrongSub : LessStrongSuper { id subIvar; } @end
84 @interface MoreWeakSub : MoreWeakSuper { id subIvar; } @end
85 @interface MoreWeak2Sub : MoreWeak2Super { id subIvar; } @end
86 @interface LessWeakSub : LessWeakSuper { id subIvar; } @end
87 @interface LessWeak2Sub : LessWeak2Super { id subIvar; } @end
89 @implementation MoreStrongSub @end
90 @implementation LessStrongSub @end
91 @implementation MoreWeakSub @end
92 @implementation MoreWeak2Sub @end
93 @implementation LessWeakSub @end
94 @implementation LessWeak2Sub @end
96 @interface NoGCChangeSub : NoGCChangeSuper {
101 @implementation NoGCChangeSub @end
103 @interface RunsOf15Sub : RunsOf15 {
108 @implementation RunsOf15Sub @end
111 int main(int argc __attribute__((unused)), char **argv)
115 #if __has_feature(objc_arc)
116 testwarn("fixme check ARC layouts too");
121 rdar://5723893 anonymous bitfield ivars crash when slid
122 rdar://5724385 bitfield ivar alignment incorrect
124 Compile-time layout of Bitfields:
126 [1 skip] uint8_ivar, uint8_bitfield
128 [3 skip] uintptr_ivar
129 [4 skip] uintptr_bitfield
132 Runtime layout of Bitfields:
135 [2 skip] uint8_ivar, uint8_bitfield
137 [4 skip] uintptr_ivar
138 [5 skip] uintptr_bitfield
144 testassert(class_getInstanceSize([Bitfields class]) == 7*sizeof(void*));
146 if (objc_collectingEnabled()) {
147 const uint8_t *bitfieldlayout;
148 bitfieldlayout = class_getIvarLayout([Bitfields class]);
149 testassert(0 == ustrcmp(bitfieldlayout, "\x01\x21\x21"));
151 bitfieldlayout = class_getWeakIvarLayout([Bitfields class]);
152 testassert(bitfieldlayout == NULL);
156 Compile-time layout of Sub:
163 Runtime layout of Sub:
171 Also, superIvar is only one byte, so subIvar's alignment must
172 be handled correctly.
174 fixme test more layouts
178 static Sub * volatile sub;
181 testassert(((uintptr_t *)objc_unretainedPointer(sub))[2] == 10);
184 testassert(((uintptr_t *)objc_unretainedPointer(sub))[5] == 1);
185 testassert(sub->cxx.magic == 1);
187 testassert(((uintptr_t *)objc_unretainedPointer(sub))[5] == 2);
188 testassert(sub->cxx.magic == 2);
189 # if __has_feature(objc_arc)
192 if (! objc_collectingEnabled()) {
195 // hack - can't get collector to reliably delete the object
199 testassert(CXX::count == 2);
202 testassert(class_getInstanceSize([Sub class]) == 6*sizeof(void*));
204 ivar = class_getInstanceVariable([Sub class], "subIvar");
206 testassert(2*sizeof(void*) == (size_t)ivar_getOffset(ivar));
207 testassert(0 == strcmp(ivar_getName(ivar), "subIvar"));
208 // rdar://7466570 clang miscompiles assert(#if __LP64__ ... #endif)
210 testassert(0 == strcmp(ivar_getTypeEncoding(ivar), "Q"));
212 testassert(0 == strcmp(ivar_getTypeEncoding(ivar), "L"));
214 testassert(0 == strcmp(ivar_getTypeEncoding(ivar), "I"));
218 ivar = class_getInstanceVariable([Sub class], "cxx");
222 ivar = class_getInstanceVariable([Super class], "superIvar");
224 testassert(sizeof(void*) == (size_t)ivar_getOffset(ivar));
225 testassert(0 == strcmp(ivar_getName(ivar), "superIvar"));
226 testassert(0 == strcmp(ivar_getTypeEncoding(ivar), "c"));
228 ivar = class_getInstanceVariable([Super class], "subIvar");
231 if (objc_collectingEnabled()) {
232 const uint8_t *superlayout;
233 const uint8_t *sublayout;
234 superlayout = class_getIvarLayout([Super class]);
235 sublayout = class_getIvarLayout([Sub class]);
236 testassert(0 == ustrcmp(superlayout, "\x01\x10"));
237 testassert(0 == ustrcmp(sublayout, "\x01\x21\x20"));
239 superlayout = class_getWeakIvarLayout([Super class]);
240 sublayout = class_getWeakIvarLayout([Sub class]);
241 testassert(superlayout == NULL);
242 testassert(0 == ustrcmp(sublayout, "\x41\x10"));
246 Shrinking superclass.
247 Subclass ivars do not compact, but the GC layout needs to
248 update, including the gap that the superclass no longer spans.
250 Compile-time layout of Sub2:
253 [6-10 weak] superIvar2
257 Runtime layout of Sub2:
259 [1-10 skip] was superIvar
264 Sub2 *sub2 = [Sub2 new];
265 sub2->isa = [Sub2 class];
266 sub2->subIvar = (void *)10;
267 testassert(((uintptr_t *)objc_unretainedPointer(sub2))[11] == 10);
269 testassert(class_getInstanceSize([Sub2 class]) == 13*sizeof(void*));
271 ivar = class_getInstanceVariable([Sub2 class], "subIvar");
273 testassert(11*sizeof(void*) == (size_t)ivar_getOffset(ivar));
274 testassert(0 == strcmp(ivar_getName(ivar), "subIvar"));
276 ivar = class_getInstanceVariable([ShrinkingSuper class], "superIvar");
279 if (objc_collectingEnabled()) {
280 const uint8_t *superlayout;
281 const uint8_t *sublayout;
282 superlayout = class_getIvarLayout([ShrinkingSuper class]);
283 sublayout = class_getIvarLayout([Sub2 class]);
284 // only `isa` is left; superIvar[] and superIvar2[] are gone
285 testassert(superlayout == NULL || 0 == ustrcmp(superlayout, "\x01"));
286 testassert(0 == ustrcmp(sublayout, "\x01\xb1"));
288 superlayout = class_getWeakIvarLayout([ShrinkingSuper class]);
289 sublayout = class_getWeakIvarLayout([Sub2 class]);
290 testassert(superlayout == NULL);
291 testassert(0 == ustrcmp(sublayout, "\xb1\x10"));
295 Ivars slide but GC layouts stay the same
296 Here, the last word of the superclass is misaligned, but
297 its GC layout includes a bit for that whole word.
298 Additionally, all of the subclass ivars fit into that word too,
299 both before and after sliding.
300 The runtime will try to slide the GC layout and must not be
301 confused (rdar://6851700). Note that the second skip-word may or may
302 not actually be included, because it crosses the end of the object.
305 Compile-time layout of NoGCChangeSub:
308 [2 skip] superc1, subc3
310 Runtime layout of NoGCChangeSub:
313 [2 skip] superc1, superc2, subc3
315 if (objc_collectingEnabled()) {
316 Ivar ivar1 = class_getInstanceVariable([NoGCChangeSub class], "superc1");
318 Ivar ivar2 = class_getInstanceVariable([NoGCChangeSub class], "superc2");
320 Ivar ivar3 = class_getInstanceVariable([NoGCChangeSub class], "subc3");
322 testassert(ivar_getOffset(ivar1) != ivar_getOffset(ivar2) &&
323 ivar_getOffset(ivar1) != ivar_getOffset(ivar3) &&
324 ivar_getOffset(ivar2) != ivar_getOffset(ivar3));
327 /* Ivar layout includes runs of 15 words.
328 rdar://6859875 this would generate a truncated GC layout.
330 if (objc_collectingEnabled()) {
331 const uint8_t *layout =
332 class_getIvarLayout(objc_getClass("RunsOf15Sub"));
336 // should find 30+ each of skip and scan
338 while ((c = *layout++)) {
342 testassert(totalSkip >= 30);
343 testassert(totalScan >= 30);
352 Classes do not change size, but GC layouts must be updated.
353 Both new and old ABI detect this case (rdar://5774578)
355 Compile-time layout of MoreStrongSub:
360 Runtime layout of MoreStrongSub:
365 testassert(class_getInstanceSize([MoreStrongSub class]) == 3*sizeof(void*));
366 if (objc_collectingEnabled()) {
367 const uint8_t *layout;
368 layout = class_getIvarLayout([MoreStrongSub class]);
369 testassert(layout == NULL);
371 layout = class_getWeakIvarLayout([MoreStrongSub class]);
372 testassert(layout == NULL);
378 Classes do not change size, but GC layouts must be updated.
379 Old ABI intentionally does not detect this case (rdar://5774578)
381 Compile-time layout of MoreWeakSub:
386 Runtime layout of MoreWeakSub:
391 testassert(class_getInstanceSize([MoreWeakSub class]) == 3*sizeof(void*));
392 if (objc_collectingEnabled()) {
393 const uint8_t *layout;
394 layout = class_getIvarLayout([MoreWeakSub class]);
396 // fixed version: scan / weak / scan
397 testassert(0 == ustrcmp(layout, "\x01\x11"));
399 // unfixed version: scan / scan / scan
400 testassert(layout == NULL || 0 == ustrcmp(layout, "\x03"));
403 layout = class_getWeakIvarLayout([MoreWeakSub class]);
405 testassert(0 == ustrcmp(layout, "\x11\x10"));
407 testassert(layout == NULL);
414 Classes do not change size, but GC layouts must be updated.
415 Old ABI intentionally does not detect this case (rdar://5774578)
417 Compile-time layout of MoreWeak2Sub:
422 Runtime layout of MoreWeak2Sub:
427 testassert(class_getInstanceSize([MoreWeak2Sub class]) == 3*sizeof(void*));
428 if (objc_collectingEnabled()) {
429 const uint8_t *layout;
430 layout = class_getIvarLayout([MoreWeak2Sub class]);
431 testassert(0 == ustrcmp(layout, "\x01\x11") ||
432 0 == ustrcmp(layout, "\x01\x10\x01"));
434 layout = class_getWeakIvarLayout([MoreWeak2Sub class]);
436 testassert(0 == ustrcmp(layout, "\x11\x10"));
438 testassert(layout == NULL);
445 Classes do not change size, but GC layouts must be updated.
446 Old ABI intentionally does not detect this case (rdar://5774578)
448 Compile-time layout of LessStrongSub:
453 Runtime layout of LessStrongSub:
458 testassert(class_getInstanceSize([LessStrongSub class]) == 3*sizeof(void*));
459 if (objc_collectingEnabled()) {
460 const uint8_t *layout;
461 layout = class_getIvarLayout([LessStrongSub class]);
463 // fixed version: scan / skip / scan
464 testassert(0 == ustrcmp(layout, "\x01\x11"));
466 // unfixed version: scan / scan / scan
467 testassert(layout == NULL || 0 == ustrcmp(layout, "\x03"));
470 layout = class_getWeakIvarLayout([LessStrongSub class]);
471 testassert(layout == NULL);
477 Classes do not change size, but GC layouts must be updated.
478 Both new and old ABI detect this case (rdar://5774578 rdar://6924114)
480 Compile-time layout of LessWeakSub:
485 Runtime layout of LessWeakSub:
490 testassert(class_getInstanceSize([LessWeakSub class]) == 3*sizeof(void*));
491 if (objc_collectingEnabled()) {
492 const uint8_t *layout;
493 layout = class_getIvarLayout([LessWeakSub class]);
494 testassert(layout == NULL);
496 layout = class_getWeakIvarLayout([LessWeakSub class]);
497 testassert(layout == NULL);
503 Classes do not change size, but GC layouts must be updated.
504 Old ABI intentionally does not detect this case (rdar://5774578)
506 Compile-time layout of LessWeak2Sub:
511 Runtime layout of LessWeak2Sub:
516 testassert(class_getInstanceSize([LessWeak2Sub class]) == 3*sizeof(void*));
517 if (objc_collectingEnabled()) {
518 const uint8_t *layout;
519 layout = class_getIvarLayout([LessWeak2Sub class]);
520 testassert(0 == ustrcmp(layout, "\x01\x11") ||
521 0 == ustrcmp(layout, "\x01\x10\x01"));
523 layout = class_getWeakIvarLayout([LessWeak2Sub class]);
525 testassert(layout == NULL);
527 testassert(0 == ustrcmp(layout, "\x11\x10"));
532 succeed(basename(argv[0]));