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->subIvar = (void *)10;
266 testassert(((uintptr_t *)objc_unretainedPointer(sub2))[11] == 10);
268 testassert(class_getInstanceSize([Sub2 class]) == 13*sizeof(void*));
270 ivar = class_getInstanceVariable([Sub2 class], "subIvar");
272 testassert(11*sizeof(void*) == (size_t)ivar_getOffset(ivar));
273 testassert(0 == strcmp(ivar_getName(ivar), "subIvar"));
275 ivar = class_getInstanceVariable([ShrinkingSuper class], "superIvar");
278 if (objc_collectingEnabled()) {
279 const uint8_t *superlayout;
280 const uint8_t *sublayout;
281 superlayout = class_getIvarLayout([ShrinkingSuper class]);
282 sublayout = class_getIvarLayout([Sub2 class]);
283 // only `isa` is left; superIvar[] and superIvar2[] are gone
284 testassert(superlayout == NULL || 0 == ustrcmp(superlayout, "\x01"));
285 testassert(0 == ustrcmp(sublayout, "\x01\xb1"));
287 superlayout = class_getWeakIvarLayout([ShrinkingSuper class]);
288 sublayout = class_getWeakIvarLayout([Sub2 class]);
289 testassert(superlayout == NULL);
290 testassert(0 == ustrcmp(sublayout, "\xb1\x10"));
294 Ivars slide but GC layouts stay the same
295 Here, the last word of the superclass is misaligned, but
296 its GC layout includes a bit for that whole word.
297 Additionally, all of the subclass ivars fit into that word too,
298 both before and after sliding.
299 The runtime will try to slide the GC layout and must not be
300 confused (rdar://6851700). Note that the second skip-word may or may
301 not actually be included, because it crosses the end of the object.
304 Compile-time layout of NoGCChangeSub:
307 [2 skip] superc1, subc3
309 Runtime layout of NoGCChangeSub:
312 [2 skip] superc1, superc2, subc3
314 if (objc_collectingEnabled()) {
315 Ivar ivar1 = class_getInstanceVariable([NoGCChangeSub class], "superc1");
317 Ivar ivar2 = class_getInstanceVariable([NoGCChangeSub class], "superc2");
319 Ivar ivar3 = class_getInstanceVariable([NoGCChangeSub class], "subc3");
321 testassert(ivar_getOffset(ivar1) != ivar_getOffset(ivar2) &&
322 ivar_getOffset(ivar1) != ivar_getOffset(ivar3) &&
323 ivar_getOffset(ivar2) != ivar_getOffset(ivar3));
326 /* Ivar layout includes runs of 15 words.
327 rdar://6859875 this would generate a truncated GC layout.
329 if (objc_collectingEnabled()) {
330 const uint8_t *layout =
331 class_getIvarLayout(objc_getClass("RunsOf15Sub"));
335 // should find 30+ each of skip and scan
337 while ((c = *layout++)) {
341 testassert(totalSkip >= 30);
342 testassert(totalScan >= 30);
351 Classes do not change size, but GC layouts must be updated.
352 Both new and old ABI detect this case (rdar://5774578)
354 Compile-time layout of MoreStrongSub:
359 Runtime layout of MoreStrongSub:
364 testassert(class_getInstanceSize([MoreStrongSub class]) == 3*sizeof(void*));
365 if (objc_collectingEnabled()) {
366 const uint8_t *layout;
367 layout = class_getIvarLayout([MoreStrongSub class]);
368 testassert(layout == NULL);
370 layout = class_getWeakIvarLayout([MoreStrongSub class]);
371 testassert(layout == NULL);
377 Classes do not change size, but GC layouts must be updated.
378 Old ABI intentionally does not detect this case (rdar://5774578)
380 Compile-time layout of MoreWeakSub:
385 Runtime layout of MoreWeakSub:
390 testassert(class_getInstanceSize([MoreWeakSub class]) == 3*sizeof(void*));
391 if (objc_collectingEnabled()) {
392 const uint8_t *layout;
393 layout = class_getIvarLayout([MoreWeakSub class]);
395 // fixed version: scan / weak / scan
396 testassert(0 == ustrcmp(layout, "\x01\x11"));
398 // unfixed version: scan / scan / scan
399 testassert(layout == NULL || 0 == ustrcmp(layout, "\x03"));
402 layout = class_getWeakIvarLayout([MoreWeakSub class]);
404 testassert(0 == ustrcmp(layout, "\x11\x10"));
406 testassert(layout == NULL);
413 Classes do not change size, but GC layouts must be updated.
414 Old ABI intentionally does not detect this case (rdar://5774578)
416 Compile-time layout of MoreWeak2Sub:
421 Runtime layout of MoreWeak2Sub:
426 testassert(class_getInstanceSize([MoreWeak2Sub class]) == 3*sizeof(void*));
427 if (objc_collectingEnabled()) {
428 const uint8_t *layout;
429 layout = class_getIvarLayout([MoreWeak2Sub class]);
430 testassert(0 == ustrcmp(layout, "\x01\x11") ||
431 0 == ustrcmp(layout, "\x01\x10\x01"));
433 layout = class_getWeakIvarLayout([MoreWeak2Sub class]);
435 testassert(0 == ustrcmp(layout, "\x11\x10"));
437 testassert(layout == NULL);
444 Classes do not change size, but GC layouts must be updated.
445 Old ABI intentionally does not detect this case (rdar://5774578)
447 Compile-time layout of LessStrongSub:
452 Runtime layout of LessStrongSub:
457 testassert(class_getInstanceSize([LessStrongSub class]) == 3*sizeof(void*));
458 if (objc_collectingEnabled()) {
459 const uint8_t *layout;
460 layout = class_getIvarLayout([LessStrongSub class]);
462 // fixed version: scan / skip / scan
463 testassert(0 == ustrcmp(layout, "\x01\x11"));
465 // unfixed version: scan / scan / scan
466 testassert(layout == NULL || 0 == ustrcmp(layout, "\x03"));
469 layout = class_getWeakIvarLayout([LessStrongSub class]);
470 testassert(layout == NULL);
476 Classes do not change size, but GC layouts must be updated.
477 Both new and old ABI detect this case (rdar://5774578 rdar://6924114)
479 Compile-time layout of LessWeakSub:
484 Runtime layout of LessWeakSub:
489 testassert(class_getInstanceSize([LessWeakSub class]) == 3*sizeof(void*));
490 if (objc_collectingEnabled()) {
491 const uint8_t *layout;
492 layout = class_getIvarLayout([LessWeakSub class]);
493 testassert(layout == NULL);
495 layout = class_getWeakIvarLayout([LessWeakSub class]);
496 testassert(layout == NULL);
502 Classes do not change size, but GC layouts must be updated.
503 Old ABI intentionally does not detect this case (rdar://5774578)
505 Compile-time layout of LessWeak2Sub:
510 Runtime layout of LessWeak2Sub:
515 testassert(class_getInstanceSize([LessWeak2Sub class]) == 3*sizeof(void*));
516 if (objc_collectingEnabled()) {
517 const uint8_t *layout;
518 layout = class_getIvarLayout([LessWeak2Sub class]);
519 testassert(0 == ustrcmp(layout, "\x01\x11") ||
520 0 == ustrcmp(layout, "\x01\x10\x01"));
522 layout = class_getWeakIvarLayout([LessWeak2Sub class]);
524 testassert(layout == NULL);
526 testassert(0 == ustrcmp(layout, "\x11\x10"));
531 succeed(basename(argv[0]));