3 $C{COMPILE} -fobjc-weak $DIR/ivarSlide1.m $DIR/ivarSlide.m -o ivarSlide.exe
10 #include <objc/objc-runtime.h>
11 #include <objc/objc-auto.h>
13 // fixme should check ARC layout handling
14 // current test checks GC layout handling which is dead
15 #define FIXME_CHECK_ARC_LAYOUTS 0
17 // ARC doesn't like __strong void* or __weak void*
22 #include "ivarSlide.h"
24 #define ustrcmp(a, b) strcmp((char *)a, (char *)b)
29 static uintptr_t count;
32 ~CXX() { count += magic; }
37 @interface Bitfields : Super {
39 uint8_t uint8_bitfield1 :7;
40 uint8_t uint8_bitfield2 :1;
44 uintptr_t uintptr_ivar;
45 uintptr_t /*uintptr_bitfield1*/ :31; // anonymous (rdar://5723893)
46 uintptr_t uintptr_bitfield2 :1;
52 @implementation Bitfields @end
55 @interface Sub : Super {
58 gc_strong void* subIvar2;
59 gc_weak void* subIvar3;
69 @implementation Sub @end
72 @interface Sub2 : ShrinkingSuper {
74 gc_weak void* subIvar;
75 gc_strong void* subIvar2;
79 @implementation Sub2 @end
81 @interface MoreStrongSub : MoreStrongSuper { id subIvar; } @end
82 @interface LessStrongSub : LessStrongSuper { id subIvar; } @end
83 @interface MoreWeakSub : MoreWeakSuper { id subIvar; } @end
84 @interface MoreWeak2Sub : MoreWeak2Super { id subIvar; } @end
85 @interface LessWeakSub : LessWeakSuper { id subIvar; } @end
86 @interface LessWeak2Sub : LessWeak2Super { id subIvar; } @end
88 @implementation MoreStrongSub @end
89 @implementation LessStrongSub @end
90 @implementation MoreWeakSub @end
91 @implementation MoreWeak2Sub @end
92 @implementation LessWeakSub @end
93 @implementation LessWeak2Sub @end
95 @interface NoGCChangeSub : NoGCChangeSuper {
100 @implementation NoGCChangeSub @end
102 @interface RunsOf15Sub : RunsOf15 {
107 @implementation RunsOf15Sub @end
110 int main(int argc __attribute__((unused)), char **argv)
112 #if __has_feature(objc_arc)
113 testwarn("fixme check ARC layouts too");
118 rdar://5723893 anonymous bitfield ivars crash when slid
119 rdar://5724385 bitfield ivar alignment incorrect
121 Compile-time layout of Bitfields:
123 [1 skip] uint8_ivar, uint8_bitfield
125 [3 skip] uintptr_ivar
126 [4 skip] uintptr_bitfield
129 Runtime layout of Bitfields:
132 [2 skip] uint8_ivar, uint8_bitfield
134 [4 skip] uintptr_ivar
135 [5 skip] uintptr_bitfield
141 testassert(class_getInstanceSize([Bitfields class]) == 7*sizeof(void*));
143 if (FIXME_CHECK_ARC_LAYOUTS) {
144 const uint8_t *bitfieldlayout;
145 bitfieldlayout = class_getIvarLayout([Bitfields class]);
146 testassert(0 == ustrcmp(bitfieldlayout, "\x01\x21\x21"));
148 bitfieldlayout = class_getWeakIvarLayout([Bitfields class]);
149 testassert(bitfieldlayout == NULL);
153 Compile-time layout of Sub:
160 Runtime layout of Sub:
168 Also, superIvar is only one byte, so subIvar's alignment must
169 be handled correctly.
171 fixme test more layouts
175 static Sub * volatile sub;
178 uintptr_t *subwords = (uintptr_t *)(__bridge void*)sub;
179 testassert(subwords[2] == 10);
182 testassert(subwords[5] == 1);
183 testassert(sub->cxx.magic == 1);
185 testassert(subwords[5] == 2);
186 testassert(sub->cxx.magic == 2);
187 # if __has_feature(objc_arc)
192 testassert(CXX::count == 2);
195 testassert(class_getInstanceSize([Sub class]) == 6*sizeof(void*));
197 ivar = class_getInstanceVariable([Sub class], "subIvar");
199 testassert(2*sizeof(void*) == (size_t)ivar_getOffset(ivar));
200 testassert(0 == strcmp(ivar_getName(ivar), "subIvar"));
201 testassert(0 == strcmp(ivar_getTypeEncoding(ivar),
210 ivar = class_getInstanceVariable([Sub class], "cxx");
214 ivar = class_getInstanceVariable([Super class], "superIvar");
216 testassert(sizeof(void*) == (size_t)ivar_getOffset(ivar));
217 testassert(0 == strcmp(ivar_getName(ivar), "superIvar"));
218 testassert(0 == strcmp(ivar_getTypeEncoding(ivar), "c"));
220 ivar = class_getInstanceVariable([Super class], "subIvar");
223 if (FIXME_CHECK_ARC_LAYOUTS) {
224 const uint8_t *superlayout;
225 const uint8_t *sublayout;
226 superlayout = class_getIvarLayout([Super class]);
227 sublayout = class_getIvarLayout([Sub class]);
228 testassert(0 == ustrcmp(superlayout, "\x01\x10"));
229 testassert(0 == ustrcmp(sublayout, "\x01\x21\x20"));
231 superlayout = class_getWeakIvarLayout([Super class]);
232 sublayout = class_getWeakIvarLayout([Sub class]);
233 testassert(superlayout == NULL);
234 testassert(0 == ustrcmp(sublayout, "\x41\x10"));
238 Shrinking superclass.
239 Subclass ivars do not compact, but the GC layout needs to
240 update, including the gap that the superclass no longer spans.
242 Compile-time layout of Sub2:
245 [6-10 weak] superIvar2
249 Runtime layout of Sub2:
251 [1-10 skip] was superIvar
256 Sub2 *sub2 = [Sub2 new];
257 uintptr_t *sub2words = (uintptr_t *)(__bridge void*)sub2;
258 sub2->subIvar = (void *)10;
259 testassert(sub2words[11] == 10);
261 testassert(class_getInstanceSize([Sub2 class]) == 13*sizeof(void*));
263 ivar = class_getInstanceVariable([Sub2 class], "subIvar");
265 testassert(11*sizeof(void*) == (size_t)ivar_getOffset(ivar));
266 testassert(0 == strcmp(ivar_getName(ivar), "subIvar"));
268 ivar = class_getInstanceVariable([ShrinkingSuper class], "superIvar");
271 if (FIXME_CHECK_ARC_LAYOUTS) {
272 const uint8_t *superlayout;
273 const uint8_t *sublayout;
274 superlayout = class_getIvarLayout([ShrinkingSuper class]);
275 sublayout = class_getIvarLayout([Sub2 class]);
276 // only `isa` is left; superIvar[] and superIvar2[] are gone
277 testassert(superlayout == NULL || 0 == ustrcmp(superlayout, "\x01"));
278 testassert(0 == ustrcmp(sublayout, "\x01\xb1"));
280 superlayout = class_getWeakIvarLayout([ShrinkingSuper class]);
281 sublayout = class_getWeakIvarLayout([Sub2 class]);
282 testassert(superlayout == NULL);
283 testassert(0 == ustrcmp(sublayout, "\xb1\x10"));
287 Ivars slide but GC layouts stay the same
288 Here, the last word of the superclass is misaligned, but
289 its GC layout includes a bit for that whole word.
290 Additionally, all of the subclass ivars fit into that word too,
291 both before and after sliding.
292 The runtime will try to slide the GC layout and must not be
293 confused (rdar://6851700). Note that the second skip-word may or may
294 not actually be included, because it crosses the end of the object.
297 Compile-time layout of NoGCChangeSub:
300 [2 skip] superc1, subc3
302 Runtime layout of NoGCChangeSub:
305 [2 skip] superc1, superc2, subc3
307 if (FIXME_CHECK_ARC_LAYOUTS) {
308 Ivar ivar1 = class_getInstanceVariable([NoGCChangeSub class], "superc1");
310 Ivar ivar2 = class_getInstanceVariable([NoGCChangeSub class], "superc2");
312 Ivar ivar3 = class_getInstanceVariable([NoGCChangeSub class], "subc3");
314 testassert(ivar_getOffset(ivar1) != ivar_getOffset(ivar2) &&
315 ivar_getOffset(ivar1) != ivar_getOffset(ivar3) &&
316 ivar_getOffset(ivar2) != ivar_getOffset(ivar3));
319 /* Ivar layout includes runs of 15 words.
320 rdar://6859875 this would generate a truncated GC layout.
322 if (FIXME_CHECK_ARC_LAYOUTS) {
323 const uint8_t *layout =
324 class_getIvarLayout(objc_getClass("RunsOf15Sub"));
328 // should find 30+ each of skip and scan
330 while ((c = *layout++)) {
334 testassert(totalSkip >= 30);
335 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 (FIXME_CHECK_ARC_LAYOUTS) {
356 const uint8_t *layout;
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 (FIXME_CHECK_ARC_LAYOUTS) {
382 const uint8_t *layout;
383 layout = class_getIvarLayout([MoreWeakSub class]);
384 testassert(0 == ustrcmp(layout, "\x01\x11"));
386 layout = class_getWeakIvarLayout([MoreWeakSub class]);
387 testassert(0 == ustrcmp(layout, "\x11\x10"));
393 Classes do not change size, but GC layouts must be updated.
394 Old ABI intentionally does not detect this case (rdar://5774578)
396 Compile-time layout of MoreWeak2Sub:
401 Runtime layout of MoreWeak2Sub:
406 testassert(class_getInstanceSize([MoreWeak2Sub class]) == 3*sizeof(void*));
407 if (FIXME_CHECK_ARC_LAYOUTS) {
408 const uint8_t *layout;
409 layout = class_getIvarLayout([MoreWeak2Sub class]);
410 testassert(0 == ustrcmp(layout, "\x01\x11") ||
411 0 == ustrcmp(layout, "\x01\x10\x01"));
413 layout = class_getWeakIvarLayout([MoreWeak2Sub class]);
414 testassert(0 == ustrcmp(layout, "\x11\x10"));
420 Classes do not change size, but GC layouts must be updated.
421 Old ABI intentionally does not detect this case (rdar://5774578)
423 Compile-time layout of LessStrongSub:
428 Runtime layout of LessStrongSub:
433 testassert(class_getInstanceSize([LessStrongSub class]) == 3*sizeof(void*));
434 if (FIXME_CHECK_ARC_LAYOUTS) {
435 const uint8_t *layout;
436 layout = class_getIvarLayout([LessStrongSub class]);
437 testassert(0 == ustrcmp(layout, "\x01\x11"));
439 layout = class_getWeakIvarLayout([LessStrongSub class]);
440 testassert(layout == NULL);
446 Classes do not change size, but GC layouts must be updated.
447 Both new and old ABI detect this case (rdar://5774578 rdar://6924114)
449 Compile-time layout of LessWeakSub:
454 Runtime layout of LessWeakSub:
459 testassert(class_getInstanceSize([LessWeakSub class]) == 3*sizeof(void*));
460 if (FIXME_CHECK_ARC_LAYOUTS) {
461 const uint8_t *layout;
462 layout = class_getIvarLayout([LessWeakSub class]);
463 testassert(layout == NULL);
465 layout = class_getWeakIvarLayout([LessWeakSub class]);
466 testassert(layout == NULL);
472 Classes do not change size, but GC layouts must be updated.
473 Old ABI intentionally does not detect this case (rdar://5774578)
475 Compile-time layout of LessWeak2Sub:
480 Runtime layout of LessWeak2Sub:
485 testassert(class_getInstanceSize([LessWeak2Sub class]) == 3*sizeof(void*));
486 if (FIXME_CHECK_ARC_LAYOUTS) {
487 const uint8_t *layout;
488 layout = class_getIvarLayout([LessWeak2Sub class]);
489 testassert(0 == ustrcmp(layout, "\x01\x11") ||
490 0 == ustrcmp(layout, "\x01\x10\x01"));
492 layout = class_getWeakIvarLayout([LessWeak2Sub class]);
493 testassert(layout == NULL);
497 succeed(basename(argv[0]));