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)
26 // Aliasing-friendly way to read from a fixed offset in an object.
27 uintptr_t readWord(id obj, int offset) {
29 char *ptr = (char *)(__bridge void*)obj;
30 memcpy(&value, ptr + offset * sizeof(uintptr_t), sizeof(uintptr_t));
37 static uintptr_t count;
40 ~CXX() { count += magic; }
45 @interface Bitfields : Super {
47 uint8_t uint8_bitfield1 :7;
48 uint8_t uint8_bitfield2 :1;
52 uintptr_t uintptr_ivar;
53 uintptr_t /*uintptr_bitfield1*/ :31; // anonymous (rdar://5723893)
54 uintptr_t uintptr_bitfield2 :1;
60 @implementation Bitfields @end
63 @interface Sub : Super {
66 gc_strong void* subIvar2;
67 gc_weak void* subIvar3;
77 @implementation Sub @end
80 @interface Sub2 : ShrinkingSuper {
82 gc_weak void* subIvar;
83 gc_strong void* subIvar2;
87 @implementation Sub2 @end
89 @interface MoreStrongSub : MoreStrongSuper { id subIvar; } @end
90 @interface LessStrongSub : LessStrongSuper { id subIvar; } @end
91 @interface MoreWeakSub : MoreWeakSuper { id subIvar; } @end
92 @interface MoreWeak2Sub : MoreWeak2Super { id subIvar; } @end
93 @interface LessWeakSub : LessWeakSuper { id subIvar; } @end
94 @interface LessWeak2Sub : LessWeak2Super { id subIvar; } @end
96 @implementation MoreStrongSub @end
97 @implementation LessStrongSub @end
98 @implementation MoreWeakSub @end
99 @implementation MoreWeak2Sub @end
100 @implementation LessWeakSub @end
101 @implementation LessWeak2Sub @end
103 @interface NoGCChangeSub : NoGCChangeSuper {
108 @implementation NoGCChangeSub @end
110 @interface RunsOf15Sub : RunsOf15 {
115 @implementation RunsOf15Sub @end
118 int main(int argc __attribute__((unused)), char **argv)
120 #if __has_feature(objc_arc)
121 testwarn("fixme check ARC layouts too");
126 rdar://5723893 anonymous bitfield ivars crash when slid
127 rdar://5724385 bitfield ivar alignment incorrect
129 Compile-time layout of Bitfields:
131 [1 skip] uint8_ivar, uint8_bitfield
133 [3 skip] uintptr_ivar
134 [4 skip] uintptr_bitfield
137 Runtime layout of Bitfields:
140 [2 skip] uint8_ivar, uint8_bitfield
142 [4 skip] uintptr_ivar
143 [5 skip] uintptr_bitfield
149 testassert(class_getInstanceSize([Bitfields class]) == 7*sizeof(void*));
151 if (FIXME_CHECK_ARC_LAYOUTS) {
152 const uint8_t *bitfieldlayout;
153 bitfieldlayout = class_getIvarLayout([Bitfields class]);
154 testassert(0 == ustrcmp(bitfieldlayout, "\x01\x21\x21"));
156 bitfieldlayout = class_getWeakIvarLayout([Bitfields class]);
157 testassert(bitfieldlayout == NULL);
161 Compile-time layout of Sub:
168 Runtime layout of Sub:
176 Also, superIvar is only one byte, so subIvar's alignment must
177 be handled correctly.
179 fixme test more layouts
183 static Sub * volatile sub;
186 testassertequal(readWord(sub, 2), 10);
189 testassertequal(readWord(sub, 5), 1);
190 testassertequal(sub->cxx.magic, 1);
192 testassertequal(readWord(sub, 5), 2);
193 testassertequal(sub->cxx.magic, 2);
194 # if __has_feature(objc_arc)
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 testassert(0 == strcmp(ivar_getTypeEncoding(ivar),
217 ivar = class_getInstanceVariable([Sub class], "cxx");
221 ivar = class_getInstanceVariable([Super class], "superIvar");
223 testassert(sizeof(void*) == (size_t)ivar_getOffset(ivar));
224 testassert(0 == strcmp(ivar_getName(ivar), "superIvar"));
225 testassert(0 == strcmp(ivar_getTypeEncoding(ivar), "c"));
227 ivar = class_getInstanceVariable([Super class], "subIvar");
230 if (FIXME_CHECK_ARC_LAYOUTS) {
231 const uint8_t *superlayout;
232 const uint8_t *sublayout;
233 superlayout = class_getIvarLayout([Super class]);
234 sublayout = class_getIvarLayout([Sub class]);
235 testassert(0 == ustrcmp(superlayout, "\x01\x10"));
236 testassert(0 == ustrcmp(sublayout, "\x01\x21\x20"));
238 superlayout = class_getWeakIvarLayout([Super class]);
239 sublayout = class_getWeakIvarLayout([Sub class]);
240 testassert(superlayout == NULL);
241 testassert(0 == ustrcmp(sublayout, "\x41\x10"));
245 Shrinking superclass.
246 Subclass ivars do not compact, but the GC layout needs to
247 update, including the gap that the superclass no longer spans.
249 Compile-time layout of Sub2:
252 [6-10 weak] superIvar2
256 Runtime layout of Sub2:
258 [1-10 skip] was superIvar
263 Sub2 *sub2 = [Sub2 new];
264 sub2->subIvar = (void *)10;
265 testassertequal(readWord(sub2, 11), 10);
267 testassertequal(class_getInstanceSize([Sub2 class]), 13*sizeof(void*));
269 ivar = class_getInstanceVariable([Sub2 class], "subIvar");
271 testassertequal(11*sizeof(void*), (size_t)ivar_getOffset(ivar));
272 testassert(0 == strcmp(ivar_getName(ivar), "subIvar"));
274 ivar = class_getInstanceVariable([ShrinkingSuper class], "superIvar");
277 if (FIXME_CHECK_ARC_LAYOUTS) {
278 const uint8_t *superlayout;
279 const uint8_t *sublayout;
280 superlayout = class_getIvarLayout([ShrinkingSuper class]);
281 sublayout = class_getIvarLayout([Sub2 class]);
282 // only `isa` is left; superIvar[] and superIvar2[] are gone
283 testassert(superlayout == NULL || 0 == ustrcmp(superlayout, "\x01"));
284 testassert(0 == ustrcmp(sublayout, "\x01\xb1"));
286 superlayout = class_getWeakIvarLayout([ShrinkingSuper class]);
287 sublayout = class_getWeakIvarLayout([Sub2 class]);
288 testassert(superlayout == NULL);
289 testassert(0 == ustrcmp(sublayout, "\xb1\x10"));
293 Ivars slide but GC layouts stay the same
294 Here, the last word of the superclass is misaligned, but
295 its GC layout includes a bit for that whole word.
296 Additionally, all of the subclass ivars fit into that word too,
297 both before and after sliding.
298 The runtime will try to slide the GC layout and must not be
299 confused (rdar://6851700). Note that the second skip-word may or may
300 not actually be included, because it crosses the end of the object.
303 Compile-time layout of NoGCChangeSub:
306 [2 skip] superc1, subc3
308 Runtime layout of NoGCChangeSub:
311 [2 skip] superc1, superc2, subc3
313 if (FIXME_CHECK_ARC_LAYOUTS) {
314 Ivar ivar1 = class_getInstanceVariable([NoGCChangeSub class], "superc1");
316 Ivar ivar2 = class_getInstanceVariable([NoGCChangeSub class], "superc2");
318 Ivar ivar3 = class_getInstanceVariable([NoGCChangeSub class], "subc3");
320 testassert(ivar_getOffset(ivar1) != ivar_getOffset(ivar2) &&
321 ivar_getOffset(ivar1) != ivar_getOffset(ivar3) &&
322 ivar_getOffset(ivar2) != ivar_getOffset(ivar3));
325 /* Ivar layout includes runs of 15 words.
326 rdar://6859875 this would generate a truncated GC layout.
328 if (FIXME_CHECK_ARC_LAYOUTS) {
329 const uint8_t *layout =
330 class_getIvarLayout(objc_getClass("RunsOf15Sub"));
334 // should find 30+ each of skip and scan
336 while ((c = *layout++)) {
340 testassert(totalSkip >= 30);
341 testassert(totalScan >= 30);
347 Classes do not change size, but GC layouts must be updated.
348 Both new and old ABI detect this case (rdar://5774578)
350 Compile-time layout of MoreStrongSub:
355 Runtime layout of MoreStrongSub:
360 testassert(class_getInstanceSize([MoreStrongSub class]) == 3*sizeof(void*));
361 if (FIXME_CHECK_ARC_LAYOUTS) {
362 const uint8_t *layout;
363 layout = class_getIvarLayout([MoreStrongSub class]);
364 testassert(layout == NULL);
366 layout = class_getWeakIvarLayout([MoreStrongSub class]);
367 testassert(layout == NULL);
373 Classes do not change size, but GC layouts must be updated.
374 Old ABI intentionally does not detect this case (rdar://5774578)
376 Compile-time layout of MoreWeakSub:
381 Runtime layout of MoreWeakSub:
386 testassert(class_getInstanceSize([MoreWeakSub class]) == 3*sizeof(void*));
387 if (FIXME_CHECK_ARC_LAYOUTS) {
388 const uint8_t *layout;
389 layout = class_getIvarLayout([MoreWeakSub class]);
390 testassert(0 == ustrcmp(layout, "\x01\x11"));
392 layout = class_getWeakIvarLayout([MoreWeakSub class]);
393 testassert(0 == ustrcmp(layout, "\x11\x10"));
399 Classes do not change size, but GC layouts must be updated.
400 Old ABI intentionally does not detect this case (rdar://5774578)
402 Compile-time layout of MoreWeak2Sub:
407 Runtime layout of MoreWeak2Sub:
412 testassert(class_getInstanceSize([MoreWeak2Sub class]) == 3*sizeof(void*));
413 if (FIXME_CHECK_ARC_LAYOUTS) {
414 const uint8_t *layout;
415 layout = class_getIvarLayout([MoreWeak2Sub class]);
416 testassert(0 == ustrcmp(layout, "\x01\x11") ||
417 0 == ustrcmp(layout, "\x01\x10\x01"));
419 layout = class_getWeakIvarLayout([MoreWeak2Sub class]);
420 testassert(0 == ustrcmp(layout, "\x11\x10"));
426 Classes do not change size, but GC layouts must be updated.
427 Old ABI intentionally does not detect this case (rdar://5774578)
429 Compile-time layout of LessStrongSub:
434 Runtime layout of LessStrongSub:
439 testassert(class_getInstanceSize([LessStrongSub class]) == 3*sizeof(void*));
440 if (FIXME_CHECK_ARC_LAYOUTS) {
441 const uint8_t *layout;
442 layout = class_getIvarLayout([LessStrongSub class]);
443 testassert(0 == ustrcmp(layout, "\x01\x11"));
445 layout = class_getWeakIvarLayout([LessStrongSub class]);
446 testassert(layout == NULL);
452 Classes do not change size, but GC layouts must be updated.
453 Both new and old ABI detect this case (rdar://5774578 rdar://6924114)
455 Compile-time layout of LessWeakSub:
460 Runtime layout of LessWeakSub:
465 testassert(class_getInstanceSize([LessWeakSub class]) == 3*sizeof(void*));
466 if (FIXME_CHECK_ARC_LAYOUTS) {
467 const uint8_t *layout;
468 layout = class_getIvarLayout([LessWeakSub class]);
469 testassert(layout == NULL);
471 layout = class_getWeakIvarLayout([LessWeakSub class]);
472 testassert(layout == NULL);
478 Classes do not change size, but GC layouts must be updated.
479 Old ABI intentionally does not detect this case (rdar://5774578)
481 Compile-time layout of LessWeak2Sub:
486 Runtime layout of LessWeak2Sub:
491 testassert(class_getInstanceSize([LessWeak2Sub class]) == 3*sizeof(void*));
492 if (FIXME_CHECK_ARC_LAYOUTS) {
493 const uint8_t *layout;
494 layout = class_getIvarLayout([LessWeak2Sub class]);
495 testassert(0 == ustrcmp(layout, "\x01\x11") ||
496 0 == ustrcmp(layout, "\x01\x10\x01"));
498 layout = class_getWeakIvarLayout([LessWeak2Sub class]);
499 testassert(layout == NULL);
503 succeed(basename(argv[0]));