4 #include <objc/objc-runtime.h>
5 #include <objc/objc-auto.h>
14 static uintptr_t count;
17 ~CXX() { count += magic; }
22 @interface Bitfields : Super {
24 uint8_t uint8_bitfield1 :7;
25 uint8_t uint8_bitfield2 :1;
29 uintptr_t uintptr_ivar;
30 uintptr_t /*uintptr_bitfield1*/ :31; // anonymous (rdar://5723893)
31 uintptr_t uintptr_bitfield2 :1;
37 @implementation Bitfields @end
40 @interface Sub : Super {
43 __strong uintptr_t subIvar2;
44 __weak uintptr_t subIvar3;
54 @implementation Sub @end
57 @interface Sub2 : ShrinkingSuper {
59 __weak uintptr_t subIvar;
60 __strong uintptr_t subIvar2;
64 @implementation Sub2 @end
66 @interface MoreStrongSub : MoreStrongSuper { id subIvar; } @end
67 @interface LessStrongSub : LessStrongSuper { id subIvar; } @end
68 @interface MoreWeakSub : MoreWeakSuper { id subIvar; } @end
69 @interface MoreWeak2Sub : MoreWeak2Super { id subIvar; } @end
70 @interface LessWeakSub : LessWeakSuper { id subIvar; } @end
71 @interface LessWeak2Sub : LessWeak2Super { id subIvar; } @end
73 @implementation MoreStrongSub @end
74 @implementation LessStrongSub @end
75 @implementation MoreWeakSub @end
76 @implementation MoreWeak2Sub @end
77 @implementation LessWeakSub @end
78 @implementation LessWeak2Sub @end
80 @interface NoGCChangeSub : NoGCChangeSuper {
85 @implementation NoGCChangeSub @end
87 @interface RunsOf15Sub : RunsOf15 {
92 @implementation RunsOf15Sub @end
95 int main(int argc __attribute__((unused)), char **argv)
97 if (objc_collecting_enabled()) {
98 objc_startCollectorThread();
105 rdar://5723893 anonymous bitfield ivars crash when slid
106 rdar://5724385 bitfield ivar alignment incorrect
108 Compile-time layout of Bitfields:
110 [1 skip] uint8_ivar, uint8_bitfield
112 [3 skip] uintptr_ivar
113 [4 skip] uintptr_bitfield
116 Runtime layout of Bitfields:
119 [2 skip] uint8_ivar, uint8_bitfield
121 [4 skip] uintptr_ivar
122 [5 skip] uintptr_bitfield
128 testassert(class_getInstanceSize([Bitfields class]) == 7*sizeof(void*));
130 if (objc_collecting_enabled()) {
131 const char *bitfieldlayout;
132 bitfieldlayout = class_getIvarLayout([Bitfields class]);
133 testassert(0 == strcmp(bitfieldlayout, "\x01\x21\x21"));
135 bitfieldlayout = class_getWeakIvarLayout([Bitfields class]);
136 testassert(bitfieldlayout == NULL);
140 Compile-time layout of Sub:
147 Runtime layout of Sub:
155 Also, superIvar is only one byte, so subIvar's alignment must
156 be handled correctly.
158 fixme test more layouts
162 static Sub * volatile sub;
165 testassert(((uintptr_t *)sub)[2] == 10);
169 for (i = 0; i < 10; i++) {
170 if (i != 0) sub = [Sub new];
171 testassert(((uintptr_t *)sub)[5] == 1);
172 testassert(sub->cxx.magic == 1);
174 testassert(((uintptr_t *)sub)[5] == 2);
175 testassert(sub->cxx.magic == 2);
176 if (! objc_collecting_enabled()) {
181 if (objc_collecting_enabled()) {
182 // only require one of the objects to be reclaimed
183 objc_collect(OBJC_EXHAUSTIVE_COLLECTION | OBJC_WAIT_UNTIL_DONE);
184 objc_collect(OBJC_EXHAUSTIVE_COLLECTION | OBJC_WAIT_UNTIL_DONE);
185 testassert(CXX::count > 0 && CXX::count <= i*2 && CXX::count % 2 == 0);
188 testassert(CXX::count == i*2);
193 testassert(class_getInstanceSize([Sub class]) == 6*sizeof(void*));
195 ivar = class_getInstanceVariable([Sub class], "subIvar");
197 testassert(2*sizeof(void*) == ivar_getOffset(ivar));
198 testassert(0 == strcmp(ivar_getName(ivar), "subIvar"));
199 testassert(0 == strcmp(ivar_getTypeEncoding(ivar),
208 ivar = class_getInstanceVariable([Sub class], "cxx");
212 ivar = class_getInstanceVariable([Super class], "superIvar");
214 testassert(sizeof(void*) == ivar_getOffset(ivar));
215 testassert(0 == strcmp(ivar_getName(ivar), "superIvar"));
216 testassert(0 == strcmp(ivar_getTypeEncoding(ivar), "c"));
218 ivar = class_getInstanceVariable([Super class], "subIvar");
221 if (objc_collecting_enabled()) {
222 const char *superlayout;
223 const char *sublayout;
224 superlayout = class_getIvarLayout([Super class]);
225 sublayout = class_getIvarLayout([Sub class]);
226 testassert(0 == strcmp(superlayout, "\x01\x10"));
227 testassert(0 == strcmp(sublayout, "\x01\x21\x20"));
229 superlayout = class_getWeakIvarLayout([Super class]);
230 sublayout = class_getWeakIvarLayout([Sub class]);
231 testassert(superlayout == NULL);
232 testassert(0 == strcmp(sublayout, "\x41\x10"));
236 Shrinking superclass.
237 Subclass ivars do not compact, but the GC layout needs to
238 update, including the gap that the superclass no longer spans.
240 Compile-time layout of Sub2:
243 [6-10 weak] superIvar2
247 Runtime layout of Sub2:
249 [1-10 skip] was superIvar
254 Sub2 *sub2 = [Sub2 new];
255 sub2->isa = [Sub2 class];
257 testassert(((uintptr_t *)sub2)[11] == 10);
259 testassert(class_getInstanceSize([Sub2 class]) == 13*sizeof(void*));
261 ivar = class_getInstanceVariable([Sub2 class], "subIvar");
263 testassert(11*sizeof(void*) == ivar_getOffset(ivar));
264 testassert(0 == strcmp(ivar_getName(ivar), "subIvar"));
266 ivar = class_getInstanceVariable([ShrinkingSuper class], "superIvar");
269 if (objc_collecting_enabled()) {
270 const char *superlayout;
271 const char *sublayout;
272 superlayout = class_getIvarLayout([ShrinkingSuper class]);
273 sublayout = class_getIvarLayout([Sub2 class]);
274 testassert(superlayout == NULL);
275 testassert(0 == strcmp(sublayout, "\x01\xb1"));
277 superlayout = class_getWeakIvarLayout([ShrinkingSuper class]);
278 sublayout = class_getWeakIvarLayout([Sub2 class]);
279 testassert(superlayout == NULL);
280 testassert(0 == strcmp(sublayout, "\xb1\x10"));
284 Ivars slide but GC layouts stay the same
285 Here, the last word of the superclass is misaligned, but
286 its GC layout includes a bit for that whole word.
287 Additionally, all of the subclass ivars fit into that word too,
288 both before and after sliding.
289 The runtime will try to slide the GC layout and must not be
290 confused (rdar://6851700). Note that the second skip-word may or may
291 not actually be included, because it crosses the end of the object.
294 Compile-time layout of NoGCChangeSub:
297 [2 skip] superc1, subc3
299 Runtime layout of NoGCChangeSub:
302 [2 skip] superc1, superc2, subc3
304 if (objc_collecting_enabled()) {
305 Ivar ivar1 = class_getInstanceVariable([NoGCChangeSub class], "superc1");
307 Ivar ivar2 = class_getInstanceVariable([NoGCChangeSub class], "superc2");
309 Ivar ivar3 = class_getInstanceVariable([NoGCChangeSub class], "subc3");
311 testassert(ivar_getOffset(ivar1) != ivar_getOffset(ivar2) &&
312 ivar_getOffset(ivar1) != ivar_getOffset(ivar3) &&
313 ivar_getOffset(ivar2) != ivar_getOffset(ivar3));
316 /* Ivar layout includes runs of 15 words.
317 rdar://6859875 this would generate a truncated GC layout.
319 if (objc_collecting_enabled()) {
320 const uint8_t *layout = (const uint8_t *)
321 class_getIvarLayout(objc_getClass("RunsOf15Sub"));
325 // should find 30+ each of skip and scan
327 while ((c = *layout++)) {
331 testassert(totalSkip >= 30);
332 testassert(totalScan >= 30);
341 Classes do not change size, but GC layouts must be updated.
342 Both new and old ABI detect this case (rdar://5774578)
344 Compile-time layout of MoreStrongSub:
349 Runtime layout of MoreStrongSub:
354 testassert(class_getInstanceSize([MoreStrongSub class]) == 3*sizeof(void*));
355 if (objc_collecting_enabled()) {
357 layout = class_getIvarLayout([MoreStrongSub class]);
358 testassert(layout == NULL);
360 layout = class_getWeakIvarLayout([MoreStrongSub class]);
361 testassert(layout == NULL);
367 Classes do not change size, but GC layouts must be updated.
368 Old ABI intentionally does not detect this case (rdar://5774578)
370 Compile-time layout of MoreWeakSub:
375 Runtime layout of MoreWeakSub:
380 testassert(class_getInstanceSize([MoreWeakSub class]) == 3*sizeof(void*));
381 if (objc_collecting_enabled()) {
383 layout = class_getIvarLayout([MoreWeakSub class]);
385 testassert(0 == strcmp(layout, "\x01\x11"));
387 testassert(layout == NULL);
390 layout = class_getWeakIvarLayout([MoreWeakSub class]);
392 testassert(0 == strcmp(layout, "\x11\x10"));
394 testassert(layout == NULL);
401 Classes do not change size, but GC layouts must be updated.
402 Old ABI intentionally does not detect this case (rdar://5774578)
404 Compile-time layout of MoreWeak2Sub:
409 Runtime layout of MoreWeak2Sub:
414 testassert(class_getInstanceSize([MoreWeak2Sub class]) == 3*sizeof(void*));
415 if (objc_collecting_enabled()) {
417 layout = class_getIvarLayout([MoreWeak2Sub class]);
418 testassert(0 == strcmp(layout, "\x01\x11") ||
419 0 == strcmp(layout, "\x01\x10\x01"));
421 layout = class_getWeakIvarLayout([MoreWeak2Sub class]);
423 testassert(0 == strcmp(layout, "\x11\x10"));
425 testassert(layout == NULL);
432 Classes do not change size, but GC layouts must be updated.
433 Old ABI intentionally does not detect this case (rdar://5774578)
435 Compile-time layout of LessStrongSub:
440 Runtime layout of LessStrongSub:
445 testassert(class_getInstanceSize([LessStrongSub class]) == 3*sizeof(void*));
446 if (objc_collecting_enabled()) {
448 layout = class_getIvarLayout([LessStrongSub class]);
450 testassert(0 == strcmp(layout, "\x01\x11"));
452 testassert(layout == NULL);
455 layout = class_getWeakIvarLayout([LessStrongSub class]);
456 testassert(layout == NULL);
462 Classes do not change size, but GC layouts must be updated.
463 Both new and old ABI detect this case (rdar://5774578 rdar://6924114)
465 Compile-time layout of LessWeakSub:
470 Runtime layout of LessWeakSub:
475 testassert(class_getInstanceSize([LessWeakSub class]) == 3*sizeof(void*));
476 if (objc_collecting_enabled()) {
478 layout = class_getIvarLayout([LessWeakSub class]);
479 testassert(layout == NULL);
481 layout = class_getWeakIvarLayout([LessWeakSub class]);
482 testassert(layout == NULL);
488 Classes do not change size, but GC layouts must be updated.
489 Old ABI intentionally does not detect this case (rdar://5774578)
491 Compile-time layout of LessWeak2Sub:
496 Runtime layout of LessWeak2Sub:
501 testassert(class_getInstanceSize([LessWeak2Sub class]) == 3*sizeof(void*));
502 if (objc_collecting_enabled()) {
504 layout = class_getIvarLayout([LessWeak2Sub class]);
505 testassert(0 == strcmp(layout, "\x01\x11") ||
506 0 == strcmp(layout, "\x01\x10\x01"));
508 layout = class_getWeakIvarLayout([LessWeak2Sub class]);
510 testassert(layout == NULL);
512 testassert(0 == strcmp(layout, "\x11\x10"));
517 succeed(basename(argv[0]));