]> git.saurik.com Git - apple/objc4.git/blame - test/msgSend.m
objc4-646.tar.gz
[apple/objc4.git] / test / msgSend.m
CommitLineData
7257e56c 1// TEST_CFLAGS -Wno-unused-parameter
8972963c 2
7af964d1 3#include "test.h"
cd5f04f5 4#include "testroot.i"
8972963c 5
cd5f04f5 6#if __cplusplus && !__clang__
8972963c
A
7
8int main()
9{
cd5f04f5 10 // llvm-g++ is confused by @selector(foo::) and will never be fixed
8972963c
A
11 succeed(__FILE__);
12}
13
14#else
15
7af964d1 16#include <objc/objc.h>
cd5f04f5
A
17#include <objc/runtime.h>
18#include <objc/objc-internal.h>
8972963c
A
19#include <objc/objc-abi.h>
20
8070259c
A
21#if __arm64__
22 // no stret dispatchers
23# define SUPPORT_STRET 0
24# define objc_msgSend_stret objc_msgSend
25# define objc_msgSendSuper2_stret objc_msgSendSuper2
26# define objc_msgSend_stret_debug objc_msgSend_debug
27# define objc_msgSendSuper2_stret_debug objc_msgSendSuper2_debug
28# define method_invoke_stret method_invoke
29#else
30# define SUPPORT_STRET 1
31#endif
32
33
8972963c
A
34#if defined(__arm__)
35// rdar://8331406
36# define ALIGN_()
37#else
38# define ALIGN_() asm(".align 4");
39#endif
7af964d1 40
cd5f04f5 41@interface Super : TestRoot @end
7af964d1
A
42
43@interface Sub : Super @end
44
45static int state = 0;
46
cd5f04f5
A
47static id SELF;
48
49// for typeof() shorthand only
50id (*idmsg0)(id, SEL) __attribute__((unused));
51long long (*llmsg0)(id, SEL) __attribute__((unused));
52// struct stret (*stretmsg0)(id, SEL) __attribute__((unused));
53double (*fpmsg0)(id, SEL) __attribute__((unused));
54long double (*lfpmsg0)(id, SEL) __attribute__((unused));
55
7af964d1 56
cd5f04f5 57#define CHECK_ARGS(sel) \
7af964d1 58do { \
cd5f04f5 59 testassert(self == SELF); \
7af964d1
A
60 testassert(_cmd == sel_registerName(#sel "::::::::::::::::::::::::::::"));\
61 testassert(i1 == 1); \
62 testassert(i2 == 2); \
63 testassert(i3 == 3); \
64 testassert(i4 == 4); \
65 testassert(i5 == 5); \
66 testassert(i6 == 6); \
67 testassert(i7 == 7); \
68 testassert(i8 == 8); \
69 testassert(i9 == 9); \
70 testassert(i10 == 10); \
71 testassert(i11 == 11); \
72 testassert(i12 == 12); \
73 testassert(i13 == 13); \
74 testassert(f1 == 1.0); \
75 testassert(f2 == 2.0); \
76 testassert(f3 == 3.0); \
77 testassert(f4 == 4.0); \
78 testassert(f5 == 5.0); \
79 testassert(f6 == 6.0); \
80 testassert(f7 == 7.0); \
81 testassert(f8 == 8.0); \
82 testassert(f9 == 9.0); \
83 testassert(f10 == 10.0); \
84 testassert(f11 == 11.0); \
85 testassert(f12 == 12.0); \
86 testassert(f13 == 13.0); \
87 testassert(f14 == 14.0); \
88 testassert(f15 == 15.0); \
89} while (0)
90
cd5f04f5 91#define CHECK_ARGS_NOARG(sel) \
8972963c 92do { \
cd5f04f5 93 testassert(self == SELF); \
8972963c
A
94 testassert(_cmd == sel_registerName(#sel "_noarg"));\
95} while (0)
96
7257e56c 97id NIL_RECEIVER;
cd5f04f5 98id ID_RESULT;
7af964d1 99long long LL_RESULT = __LONG_LONG_MAX__ - 2LL*__INT_MAX__;
7af964d1
A
100double FP_RESULT = __DBL_MIN__ + __DBL_EPSILON__;
101long double LFP_RESULT = __LDBL_MIN__ + __LDBL_EPSILON__;
cd5f04f5
A
102// STRET_RESULT in test.h
103
104static struct stret zero;
7af964d1 105
8070259c
A
106struct stret_i1 {
107 uintptr_t i1;
108};
109struct stret_i2 {
110 uintptr_t i1;
111 uintptr_t i2;
112};
113struct stret_i3 {
114 uintptr_t i1;
115 uintptr_t i2;
116 uintptr_t i3;
117};
118struct stret_i4 {
119 uintptr_t i1;
120 uintptr_t i2;
121 uintptr_t i3;
122};
123struct stret_i5 {
124 uintptr_t i1;
125 uintptr_t i2;
126 uintptr_t i3;
127 uintptr_t i4;
128 uintptr_t i5;
129};
130struct stret_i6 {
131 uintptr_t i1;
132 uintptr_t i2;
133 uintptr_t i3;
134 uintptr_t i4;
135 uintptr_t i5;
136 uintptr_t i6;
137};
138struct stret_i7 {
139 uintptr_t i1;
140 uintptr_t i2;
141 uintptr_t i3;
142 uintptr_t i4;
143 uintptr_t i5;
144 uintptr_t i6;
145 uintptr_t i7;
146};
147struct stret_i8 {
148 uintptr_t i1;
149 uintptr_t i2;
150 uintptr_t i3;
151 uintptr_t i4;
152 uintptr_t i5;
153 uintptr_t i8;
154 uintptr_t i9;
155};
156struct stret_i9 {
157 uintptr_t i1;
158 uintptr_t i2;
159 uintptr_t i3;
160 uintptr_t i4;
161 uintptr_t i5;
162 uintptr_t i6;
163 uintptr_t i7;
164 uintptr_t i8;
165 uintptr_t i9;
166};
167
168struct stret_d1 {
169 double d1;
170};
171struct stret_d2 {
172 double d1;
173 double d2;
174};
175struct stret_d3 {
176 double d1;
177 double d2;
178 double d3;
179};
180struct stret_d4 {
181 double d1;
182 double d2;
183 double d3;
184};
185struct stret_d5 {
186 double d1;
187 double d2;
188 double d3;
189 double d4;
190 double d5;
191};
192struct stret_d6 {
193 double d1;
194 double d2;
195 double d3;
196 double d4;
197 double d5;
198 double d6;
199};
200struct stret_d7 {
201 double d1;
202 double d2;
203 double d3;
204 double d4;
205 double d5;
206 double d6;
207 double d7;
208};
209struct stret_d8 {
210 double d1;
211 double d2;
212 double d3;
213 double d4;
214 double d5;
215 double d8;
216 double d9;
217};
218struct stret_d9 {
219 double d1;
220 double d2;
221 double d3;
222 double d4;
223 double d5;
224 double d6;
225 double d7;
226 double d8;
227 double d9;
228};
229
7af964d1
A
230
231@implementation Super
cd5f04f5 232-(struct stret)stret { return STRET_RESULT; }
7af964d1 233
cd5f04f5 234-(id)idret:
7257e56c 235 (int)i1 :(int)i2 :(int)i3 :(int)i4 :(int)i5 :(int)i6 :(int)i7 :(int)i8 :(int)i9 :(int)i10 :(int)i11 :(int)i12 :(int)i13 :(double)f1 :(double)f2 :(double)f3 :(double)f4 :(double)f5 :(double)f6 :(double)f7 :(double)f8 :(double)f9 :(double)f10 :(double)f11 :(double)f12 :(double)f13 :(double)f14 :(double)f15
7af964d1 236{
cd5f04f5 237 CHECK_ARGS(idret);
7af964d1
A
238 state = 1;
239 return ID_RESULT;
240}
241
cd5f04f5 242-(long long)llret:
7257e56c 243 (int)i1 :(int)i2 :(int)i3 :(int)i4 :(int)i5 :(int)i6 :(int)i7 :(int)i8 :(int)i9 :(int)i10 :(int)i11 :(int)i12 :(int)i13 :(double)f1 :(double)f2 :(double)f3 :(double)f4 :(double)f5 :(double)f6 :(double)f7 :(double)f8 :(double)f9 :(double)f10 :(double)f11 :(double)f12 :(double)f13 :(double)f14 :(double)f15
7af964d1 244{
cd5f04f5 245 CHECK_ARGS(llret);
7af964d1
A
246 state = 2;
247 return LL_RESULT;
248}
249
cd5f04f5 250-(struct stret)stret:
7257e56c 251 (int)i1 :(int)i2 :(int)i3 :(int)i4 :(int)i5 :(int)i6 :(int)i7 :(int)i8 :(int)i9 :(int)i10 :(int)i11 :(int)i12 :(int)i13 :(double)f1 :(double)f2 :(double)f3 :(double)f4 :(double)f5 :(double)f6 :(double)f7 :(double)f8 :(double)f9 :(double)f10 :(double)f11 :(double)f12 :(double)f13 :(double)f14 :(double)f15
7af964d1 252{
cd5f04f5 253 CHECK_ARGS(stret);
7af964d1
A
254 state = 3;
255 return STRET_RESULT;
256}
257
cd5f04f5 258-(double)fpret:
7257e56c 259 (int)i1 :(int)i2 :(int)i3 :(int)i4 :(int)i5 :(int)i6 :(int)i7 :(int)i8 :(int)i9 :(int)i10 :(int)i11 :(int)i12 :(int)i13 :(double)f1 :(double)f2 :(double)f3 :(double)f4 :(double)f5 :(double)f6 :(double)f7 :(double)f8 :(double)f9 :(double)f10 :(double)f11 :(double)f12 :(double)f13 :(double)f14 :(double)f15
7af964d1 260{
cd5f04f5 261 CHECK_ARGS(fpret);
7af964d1
A
262 state = 4;
263 return FP_RESULT;
264}
265
cd5f04f5 266-(long double)lfpret:
7257e56c 267 (int)i1 :(int)i2 :(int)i3 :(int)i4 :(int)i5 :(int)i6 :(int)i7 :(int)i8 :(int)i9 :(int)i10 :(int)i11 :(int)i12 :(int)i13 :(double)f1 :(double)f2 :(double)f3 :(double)f4 :(double)f5 :(double)f6 :(double)f7 :(double)f8 :(double)f9 :(double)f10 :(double)f11 :(double)f12 :(double)f13 :(double)f14 :(double)f15
7af964d1 268{
cd5f04f5 269 CHECK_ARGS(lfpret);
7af964d1
A
270 state = 5;
271 return LFP_RESULT;
272}
273
274
cd5f04f5 275-(id)idret_noarg
8972963c 276{
cd5f04f5 277 CHECK_ARGS_NOARG(idret);
8972963c
A
278 state = 11;
279 return ID_RESULT;
280}
281
cd5f04f5 282-(long long)llret_noarg
8972963c 283{
cd5f04f5 284 CHECK_ARGS_NOARG(llret);
8972963c
A
285 state = 12;
286 return LL_RESULT;
287}
288
cd5f04f5 289-(struct stret)stret_noarg
8972963c 290{
cd5f04f5 291 CHECK_ARGS_NOARG(stret);
8972963c
A
292 state = 13;
293 return STRET_RESULT;
294}
8972963c 295
cd5f04f5 296-(double)fpret_noarg
8972963c 297{
cd5f04f5 298 CHECK_ARGS_NOARG(fpret);
8972963c
A
299 state = 14;
300 return FP_RESULT;
301}
302
cd5f04f5 303-(long double)lfpret_noarg
8972963c 304{
cd5f04f5 305 CHECK_ARGS_NOARG(lfpret);
8972963c
A
306 state = 15;
307 return LFP_RESULT;
308}
309
310
cd5f04f5
A
311-(void)voidret_nop
312{
313 return;
314}
315
8070259c
A
316-(void)voidret_nop2
317{
318 return;
319}
320
cd5f04f5
A
321-(id)idret_nop
322{
323 return ID_RESULT;
324}
325
326-(long long)llret_nop
327{
328 return LL_RESULT;
329}
330
331-(struct stret)stret_nop
332{
333 return STRET_RESULT;
334}
335
336-(double)fpret_nop
337{
338 return FP_RESULT;
339}
340
341-(long double)lfpret_nop
342{
343 return LFP_RESULT;
344}
345
8070259c
A
346#define STRET_IMP(n) \
347+(struct stret_##n)stret_##n##_zero \
348{ \
349 struct stret_##n ret; \
350 bzero(&ret, sizeof(ret)); \
351 return ret; \
352} \
353+(struct stret_##n)stret_##n##_nonzero \
354{ \
355 struct stret_##n ret; \
356 memset(&ret, 0xff, sizeof(ret)); \
357 return ret; \
358}
359
360STRET_IMP(i1)
361STRET_IMP(i2)
362STRET_IMP(i3)
363STRET_IMP(i4)
364STRET_IMP(i5)
365STRET_IMP(i6)
366STRET_IMP(i7)
367STRET_IMP(i8)
368STRET_IMP(i9)
369
370STRET_IMP(d1)
371STRET_IMP(d2)
372STRET_IMP(d3)
373STRET_IMP(d4)
374STRET_IMP(d5)
375STRET_IMP(d6)
376STRET_IMP(d7)
377STRET_IMP(d8)
378STRET_IMP(d9)
cd5f04f5
A
379
380
381+(id)idret:
7257e56c 382 (int)i1 :(int)i2 :(int)i3 :(int)i4 :(int)i5 :(int)i6 :(int)i7 :(int)i8 :(int)i9 :(int)i10 :(int)i11 :(int)i12 :(int)i13 :(double)f1 :(double)f2 :(double)f3 :(double)f4 :(double)f5 :(double)f6 :(double)f7 :(double)f8 :(double)f9 :(double)f10 :(double)f11 :(double)f12 :(double)f13 :(double)f14 :(double)f15
7af964d1 383{
cd5f04f5
A
384 fail("+idret called instead of -idret");
385 CHECK_ARGS(idret);
7af964d1
A
386}
387
cd5f04f5 388+(long long)llret:
7257e56c 389 (int)i1 :(int)i2 :(int)i3 :(int)i4 :(int)i5 :(int)i6 :(int)i7 :(int)i8 :(int)i9 :(int)i10 :(int)i11 :(int)i12 :(int)i13 :(double)f1 :(double)f2 :(double)f3 :(double)f4 :(double)f5 :(double)f6 :(double)f7 :(double)f8 :(double)f9 :(double)f10 :(double)f11 :(double)f12 :(double)f13 :(double)f14 :(double)f15
7af964d1 390{
cd5f04f5
A
391 fail("+llret called instead of -llret");
392 CHECK_ARGS(llret);
7af964d1
A
393}
394
cd5f04f5 395+(struct stret)stret:
7257e56c 396 (int)i1 :(int)i2 :(int)i3 :(int)i4 :(int)i5 :(int)i6 :(int)i7 :(int)i8 :(int)i9 :(int)i10 :(int)i11 :(int)i12 :(int)i13 :(double)f1 :(double)f2 :(double)f3 :(double)f4 :(double)f5 :(double)f6 :(double)f7 :(double)f8 :(double)f9 :(double)f10 :(double)f11 :(double)f12 :(double)f13 :(double)f14 :(double)f15
7af964d1 397{
cd5f04f5
A
398 fail("+stret called instead of -stret");
399 CHECK_ARGS(stret);
7af964d1
A
400}
401
cd5f04f5 402+(double)fpret:
7257e56c 403 (int)i1 :(int)i2 :(int)i3 :(int)i4 :(int)i5 :(int)i6 :(int)i7 :(int)i8 :(int)i9 :(int)i10 :(int)i11 :(int)i12 :(int)i13 :(double)f1 :(double)f2 :(double)f3 :(double)f4 :(double)f5 :(double)f6 :(double)f7 :(double)f8 :(double)f9 :(double)f10 :(double)f11 :(double)f12 :(double)f13 :(double)f14 :(double)f15
7af964d1 404{
cd5f04f5
A
405 fail("+fpret called instead of -fpret");
406 CHECK_ARGS(fpret);
7af964d1
A
407}
408
cd5f04f5 409+(long double)lfpret:
7257e56c 410 (int)i1 :(int)i2 :(int)i3 :(int)i4 :(int)i5 :(int)i6 :(int)i7 :(int)i8 :(int)i9 :(int)i10 :(int)i11 :(int)i12 :(int)i13 :(double)f1 :(double)f2 :(double)f3 :(double)f4 :(double)f5 :(double)f6 :(double)f7 :(double)f8 :(double)f9 :(double)f10 :(double)f11 :(double)f12 :(double)f13 :(double)f14 :(double)f15
7af964d1 411{
cd5f04f5
A
412 fail("+lfpret called instead of -lfpret");
413 CHECK_ARGS(lfpret);
7af964d1
A
414}
415
cd5f04f5 416+(id)idret_noarg
8972963c 417{
cd5f04f5
A
418 fail("+idret_noarg called instead of -idret_noarg");
419 CHECK_ARGS_NOARG(idret);
8972963c
A
420}
421
cd5f04f5 422+(long long)llret_noarg
8972963c 423{
cd5f04f5
A
424 fail("+llret_noarg called instead of -llret_noarg");
425 CHECK_ARGS_NOARG(llret);
8972963c
A
426}
427
cd5f04f5 428+(struct stret)stret_noarg
8972963c 429{
cd5f04f5
A
430 fail("+stret_noarg called instead of -stret_noarg");
431 CHECK_ARGS_NOARG(stret);
8972963c
A
432}
433
cd5f04f5 434+(double)fpret_noarg
8972963c 435{
cd5f04f5
A
436 fail("+fpret_noarg called instead of -fpret_noarg");
437 CHECK_ARGS_NOARG(fpret);
8972963c
A
438}
439
cd5f04f5 440+(long double)lfpret_noarg
8972963c 441{
cd5f04f5
A
442 fail("+lfpret_noarg called instead of -lfpret_noarg");
443 CHECK_ARGS_NOARG(lfpret);
8972963c
A
444}
445
7af964d1
A
446@end
447
448
449@implementation Sub
450
cd5f04f5 451-(id)idret:
7257e56c 452 (int)i1 :(int)i2 :(int)i3 :(int)i4 :(int)i5 :(int)i6 :(int)i7 :(int)i8 :(int)i9 :(int)i10 :(int)i11 :(int)i12 :(int)i13 :(double)f1 :(double)f2 :(double)f3 :(double)f4 :(double)f5 :(double)f6 :(double)f7 :(double)f8 :(double)f9 :(double)f10 :(double)f11 :(double)f12 :(double)f13 :(double)f14 :(double)f15
7af964d1
A
453{
454 id result;
cd5f04f5 455 CHECK_ARGS(idret);
8972963c 456 state = 100;
7af964d1
A
457 result = [super idret:i1:i2:i3:i4:i5:i6:i7:i8:i9:i10:i11:i12:i13:f1:f2:f3:f4:f5:f6:f7:f8:f9:f10:f11:f12:f13:f14:f15];
458 testassert(state == 1);
459 testassert(result == ID_RESULT);
8972963c 460 state = 101;
7af964d1
A
461 return result;
462}
463
cd5f04f5 464-(long long)llret:
7257e56c 465 (int)i1 :(int)i2 :(int)i3 :(int)i4 :(int)i5 :(int)i6 :(int)i7 :(int)i8 :(int)i9 :(int)i10 :(int)i11 :(int)i12 :(int)i13 :(double)f1 :(double)f2 :(double)f3 :(double)f4 :(double)f5 :(double)f6 :(double)f7 :(double)f8 :(double)f9 :(double)f10 :(double)f11 :(double)f12 :(double)f13 :(double)f14 :(double)f15
7af964d1
A
466{
467 long long result;
cd5f04f5 468 CHECK_ARGS(llret);
8972963c 469 state = 100;
7af964d1
A
470 result = [super llret:i1:i2:i3:i4:i5:i6:i7:i8:i9:i10:i11:i12:i13:f1:f2:f3:f4:f5:f6:f7:f8:f9:f10:f11:f12:f13:f14:f15];
471 testassert(state == 2);
472 testassert(result == LL_RESULT);
8972963c 473 state = 102;
7af964d1
A
474 return result;
475}
476
cd5f04f5 477-(struct stret)stret:
7257e56c 478 (int)i1 :(int)i2 :(int)i3 :(int)i4 :(int)i5 :(int)i6 :(int)i7 :(int)i8 :(int)i9 :(int)i10 :(int)i11 :(int)i12 :(int)i13 :(double)f1 :(double)f2 :(double)f3 :(double)f4 :(double)f5 :(double)f6 :(double)f7 :(double)f8 :(double)f9 :(double)f10 :(double)f11 :(double)f12 :(double)f13 :(double)f14 :(double)f15
7af964d1
A
479{
480 struct stret result;
cd5f04f5 481 CHECK_ARGS(stret);
8972963c 482 state = 100;
7af964d1
A
483 result = [super stret:i1:i2:i3:i4:i5:i6:i7:i8:i9:i10:i11:i12:i13:f1:f2:f3:f4:f5:f6:f7:f8:f9:f10:f11:f12:f13:f14:f15];
484 testassert(state == 3);
485 testassert(stret_equal(result, STRET_RESULT));
8972963c 486 state = 103;
7af964d1
A
487 return result;
488}
489
cd5f04f5 490-(double)fpret:
7257e56c 491 (int)i1 :(int)i2 :(int)i3 :(int)i4 :(int)i5 :(int)i6 :(int)i7 :(int)i8 :(int)i9 :(int)i10 :(int)i11 :(int)i12 :(int)i13 :(double)f1 :(double)f2 :(double)f3 :(double)f4 :(double)f5 :(double)f6 :(double)f7 :(double)f8 :(double)f9 :(double)f10 :(double)f11 :(double)f12 :(double)f13 :(double)f14 :(double)f15
7af964d1
A
492{
493 double result;
cd5f04f5 494 CHECK_ARGS(fpret);
8972963c 495 state = 100;
7af964d1
A
496 result = [super fpret:i1:i2:i3:i4:i5:i6:i7:i8:i9:i10:i11:i12:i13:f1:f2:f3:f4:f5:f6:f7:f8:f9:f10:f11:f12:f13:f14:f15];
497 testassert(state == 4);
498 testassert(result == FP_RESULT);
8972963c 499 state = 104;
7af964d1
A
500 return result;
501}
502
cd5f04f5 503-(long double)lfpret:
7257e56c 504 (int)i1 :(int)i2 :(int)i3 :(int)i4 :(int)i5 :(int)i6 :(int)i7 :(int)i8 :(int)i9 :(int)i10 :(int)i11 :(int)i12 :(int)i13 :(double)f1 :(double)f2 :(double)f3 :(double)f4 :(double)f5 :(double)f6 :(double)f7 :(double)f8 :(double)f9 :(double)f10 :(double)f11 :(double)f12 :(double)f13 :(double)f14 :(double)f15
7af964d1
A
505{
506 long double result;
cd5f04f5 507 CHECK_ARGS(lfpret);
8972963c 508 state = 100;
7af964d1
A
509 result = [super lfpret:i1:i2:i3:i4:i5:i6:i7:i8:i9:i10:i11:i12:i13:f1:f2:f3:f4:f5:f6:f7:f8:f9:f10:f11:f12:f13:f14:f15];
510 testassert(state == 5);
511 testassert(result == LFP_RESULT);
8972963c
A
512 state = 105;
513 return result;
514}
515
516
cd5f04f5 517-(id)idret_noarg
8972963c
A
518{
519 id result;
cd5f04f5 520 CHECK_ARGS_NOARG(idret);
8972963c
A
521 state = 100;
522 result = [super idret_noarg];
523 testassert(state == 11);
524 testassert(result == ID_RESULT);
525 state = 111;
526 return result;
527}
528
cd5f04f5 529-(long long)llret_noarg
8972963c
A
530{
531 long long result;
cd5f04f5 532 CHECK_ARGS_NOARG(llret);
8972963c
A
533 state = 100;
534 result = [super llret_noarg];
535 testassert(state == 12);
536 testassert(result == LL_RESULT);
537 state = 112;
538 return result;
539}
cd5f04f5
A
540
541-(struct stret)stret_noarg
8972963c
A
542{
543 struct stret result;
cd5f04f5 544 CHECK_ARGS_NOARG(stret);
8972963c
A
545 state = 100;
546 result = [super stret_noarg];
547 testassert(state == 13);
548 testassert(stret_equal(result, STRET_RESULT));
549 state = 113;
550 return result;
551}
cd5f04f5
A
552
553-(double)fpret_noarg
8972963c
A
554{
555 double result;
cd5f04f5 556 CHECK_ARGS_NOARG(fpret);
8972963c
A
557 state = 100;
558 result = [super fpret_noarg];
559 testassert(state == 14);
560 testassert(result == FP_RESULT);
561 state = 114;
562 return result;
563}
564
cd5f04f5 565-(long double)lfpret_noarg
8972963c
A
566{
567 long double result;
cd5f04f5 568 CHECK_ARGS_NOARG(lfpret);
8972963c
A
569 state = 100;
570 result = [super lfpret_noarg];
571 testassert(state == 15);
572 testassert(result == LFP_RESULT);
573 state = 115;
7af964d1
A
574 return result;
575}
576
cd5f04f5
A
577@end
578
579
7257e56c 580#if OBJC_HAVE_TAGGED_POINTERS
7af964d1 581
cd5f04f5 582@interface TaggedSub : Sub @end
7af964d1 583
cd5f04f5 584@implementation TaggedSub : Sub
7af964d1 585
cd5f04f5 586+(void)initialize
7af964d1 587{
7257e56c 588 _objc_registerTaggedPointerClass(OBJC_TAG_7, self);
7af964d1
A
589}
590
cd5f04f5
A
591@end
592
8070259c
A
593#endif
594
595
cd5f04f5
A
596// DWARF checking machinery
597
8070259c
A
598#if TARGET_OS_WIN32
599// unimplemented on this platform
600#elif !__OBJC2__
601// 32-bit Mac doesn't use DWARF unwind
602#elif TARGET_OS_IPHONE && __arm__
603// 32-bit iOS device doesn't use DWARF unwind
604#elif __has_feature(objc_arc)
605// ARC's extra RR calls hit the traps at the wrong times
606#else
607
608#define TEST_DWARF 1
609
610// Classes with no implementations and no cache contents from elsewhere.
611@interface SuperDW : TestRoot @end
612@implementation SuperDW @end
613
614@interface Sub0DW : SuperDW @end
615@implementation Sub0DW @end
616
617@interface SubDW : Sub0DW @end
618@implementation SubDW @end
619
cd5f04f5
A
620#include <dlfcn.h>
621#include <signal.h>
622#include <sys/mman.h>
623#include <libunwind.h>
624
625#define UNW_STEP_SUCCESS 1
626#define UNW_STEP_END 0
627
628bool caught = false;
629uintptr_t clobbered;
630
8070259c
A
631__BEGIN_DECLS
632extern void callit(void *obj, void *sel, void *fn);
633extern struct stret callit_stret(void *obj, void *sel, void *fn);
634__END_DECLS
635
636#if __x86_64__
637
638#define OTOOL "/usr/bin/xcrun otool -arch x86_64 "
639
640typedef uint8_t insn_t;
641#define BREAK_INSN ((insn_t)0xcc) // int3
642
cd5f04f5
A
643uintptr_t r12 = 0;
644uintptr_t r13 = 0;
645uintptr_t r14 = 0;
646uintptr_t r15 = 0;
647uintptr_t rbx = 0;
648uintptr_t rbp = 0;
649uintptr_t rsp = 0;
650uintptr_t rip = 0;
651
652void handle_exception(x86_thread_state64_t *state)
7af964d1 653{
cd5f04f5
A
654 unw_cursor_t curs;
655 unw_word_t reg;
656 int err;
657 int step;
658
659 err = unw_init_local(&curs, (unw_context_t *)state);
660 testassert(!err);
661
662 step = unw_step(&curs);
663 testassert(step == UNW_STEP_SUCCESS);
664
665 err = unw_get_reg(&curs, UNW_X86_64_R12, &reg);
666 testassert(!err);
667 testassert(reg == r12);
668
669 err = unw_get_reg(&curs, UNW_X86_64_R13, &reg);
670 testassert(!err);
671 testassert(reg == r13);
672
673 err = unw_get_reg(&curs, UNW_X86_64_R14, &reg);
674 testassert(!err);
675 testassert(reg == r14);
676
677 err = unw_get_reg(&curs, UNW_X86_64_R15, &reg);
678 testassert(!err);
679 testassert(reg == r15);
680
681 err = unw_get_reg(&curs, UNW_X86_64_RBX, &reg);
682 testassert(!err);
683 testassert(reg == rbx);
684
685 err = unw_get_reg(&curs, UNW_X86_64_RBP, &reg);
686 testassert(!err);
687 testassert(reg == rbp);
688
689 err = unw_get_reg(&curs, UNW_X86_64_RSP, &reg);
690 testassert(!err);
691 testassert(reg == rsp);
692
693 err = unw_get_reg(&curs, UNW_REG_IP, &reg);
694 testassert(!err);
695 testassert(reg == rip);
696
697
698 // set thread state to unwound state
699 state->__r12 = r12;
700 state->__r13 = r13;
701 state->__r14 = r14;
702 state->__r15 = r15;
703 state->__rbx = rbx;
704 state->__rbp = rbp;
705 state->__rsp = rsp;
706 state->__rip = rip;
707
708 caught = true;
7af964d1
A
709}
710
cd5f04f5
A
711
712void sigtrap(int sig, siginfo_t *info, void *cc)
7af964d1 713{
cd5f04f5
A
714 ucontext_t *uc = (ucontext_t *)cc;
715 mcontext_t mc = (mcontext_t)uc->uc_mcontext;
716
717 testprintf(" handled\n");
718
719 testassert(sig == SIGTRAP);
720 testassert((uintptr_t)info->si_addr-1 == clobbered);
721
722 handle_exception(&mc->__ss);
723 // handle_exception changed register state for continuation
7af964d1
A
724}
725
cd5f04f5
A
726__asm__(
727"\n .text"
728"\n .globl _callit"
729"\n _callit:"
8070259c 730// save sp and return address to variables
cd5f04f5
A
731"\n movq (%rsp), %r10"
732"\n movq %r10, _rip(%rip)"
733"\n movq %rsp, _rsp(%rip)"
734"\n addq $8, _rsp(%rip)" // rewind to pre-call value
735// save other non-volatile registers to variables
736"\n movq %rbx, _rbx(%rip)"
737"\n movq %rbp, _rbp(%rip)"
738"\n movq %r12, _r12(%rip)"
739"\n movq %r13, _r13(%rip)"
740"\n movq %r14, _r14(%rip)"
741"\n movq %r15, _r15(%rip)"
742"\n jmpq *%rdx"
743 );
744
745__asm__(
746"\n .text"
747"\n .globl _callit_stret"
748"\n _callit_stret:"
8070259c 749// save sp and return address to variables
cd5f04f5
A
750"\n movq (%rsp), %r10"
751"\n movq %r10, _rip(%rip)"
752"\n movq %rsp, _rsp(%rip)"
753"\n addq $8, _rsp(%rip)" // rewind to pre-call value
754// save other non-volatile registers to variables
755"\n movq %rbx, _rbx(%rip)"
756"\n movq %rbp, _rbp(%rip)"
757"\n movq %r12, _r12(%rip)"
758"\n movq %r13, _r13(%rip)"
759"\n movq %r14, _r14(%rip)"
760"\n movq %r15, _r15(%rip)"
761"\n jmpq *%rcx"
762 );
763
8070259c
A
764
765// x86_64
766
767#elif __i386__
768
769#define OTOOL "/usr/bin/xcrun otool -arch i386 "
770
771typedef uint8_t insn_t;
772#define BREAK_INSN ((insn_t)0xcc) // int3
773
774uintptr_t eip = 0;
775uintptr_t esp = 0;
776uintptr_t ebx = 0;
777uintptr_t ebp = 0;
778uintptr_t edi = 0;
779uintptr_t esi = 0;
780uintptr_t espfix = 0;
781
782void handle_exception(i386_thread_state_t *state)
783{
784 unw_cursor_t curs;
785 unw_word_t reg;
786 int err;
787 int step;
788
789 err = unw_init_local(&curs, (unw_context_t *)state);
790 testassert(!err);
791
792 step = unw_step(&curs);
793 testassert(step == UNW_STEP_SUCCESS);
794
795 err = unw_get_reg(&curs, UNW_REG_IP, &reg);
796 testassert(!err);
797 testassert(reg == eip);
798
799 err = unw_get_reg(&curs, UNW_X86_ESP, &reg);
800 testassert(!err);
801 testassert(reg == esp);
802
803 err = unw_get_reg(&curs, UNW_X86_EBX, &reg);
804 testassert(!err);
805 testassert(reg == ebx);
806
807 err = unw_get_reg(&curs, UNW_X86_EBP, &reg);
808 testassert(!err);
809 testassert(reg == ebp);
810
811 err = unw_get_reg(&curs, UNW_X86_EDI, &reg);
812 testassert(!err);
813 testassert(reg == edi);
814
815 err = unw_get_reg(&curs, UNW_X86_ESI, &reg);
816 testassert(!err);
817 testassert(reg == esi);
818
819
820 // set thread state to unwound state
821 state->__eip = eip;
822 state->__esp = esp + espfix;
823 state->__ebx = ebx;
824 state->__ebp = ebp;
825 state->__edi = edi;
826 state->__esi = esi;
827
828 caught = true;
829}
830
831
832void sigtrap(int sig, siginfo_t *info, void *cc)
833{
834 ucontext_t *uc = (ucontext_t *)cc;
835 mcontext_t mc = (mcontext_t)uc->uc_mcontext;
836
837 testprintf(" handled\n");
838
839 testassert(sig == SIGTRAP);
840 testassert((uintptr_t)info->si_addr-1 == clobbered);
841
842 handle_exception(&mc->__ss);
843 // handle_exception changed register state for continuation
844}
845
846__asm__(
847"\n .text"
848"\n .globl _callit"
849"\n _callit:"
850// save sp and return address to variables
851"\n call 1f"
852"\n 1: popl %edx"
853"\n movl (%esp), %eax"
854"\n movl %eax, _eip-1b(%edx)"
855"\n movl %esp, _esp-1b(%edx)"
856"\n addl $4, _esp-1b(%edx)" // rewind to pre-call value
857"\n movl $0, _espfix-1b(%edx)"
858// save other non-volatile registers to variables
859"\n movl %ebx, _ebx-1b(%edx)"
860"\n movl %ebp, _ebp-1b(%edx)"
861"\n movl %edi, _edi-1b(%edx)"
862"\n movl %esi, _esi-1b(%edx)"
863"\n jmpl *12(%esp)"
864 );
865
866__asm__(
867"\n .text"
868"\n .globl _callit_stret"
869"\n _callit_stret:"
870// save sp and return address to variables
871"\n call 1f"
872"\n 1: popl %edx"
873"\n movl (%esp), %eax"
874"\n movl %eax, _eip-1b(%edx)"
875"\n movl %esp, _esp-1b(%edx)"
876"\n addl $4, _esp-1b(%edx)" // rewind to pre-call value
877"\n movl $4, _espfix-1b(%edx)"
878// save other non-volatile registers to variables
879"\n movl %ebx, _ebx-1b(%edx)"
880"\n movl %ebp, _ebp-1b(%edx)"
881"\n movl %edi, _edi-1b(%edx)"
882"\n movl %esi, _esi-1b(%edx)"
883"\n jmpl *16(%esp)"
884 );
885
886
887// i386
888#elif __arm64__
889
890#include <sys/ucontext.h>
891
892// runs on iOS device, no xcrun command present
893#define OTOOL "/usr/bin/otool -arch arm64 "
894
895typedef uint32_t insn_t;
896#define BREAK_INSN ((insn_t)0xd4200020) // brk #1
897
898uintptr_t x19 = 0;
899uintptr_t x20 = 0;
900uintptr_t x21 = 0;
901uintptr_t x22 = 0;
902uintptr_t x23 = 0;
903uintptr_t x24 = 0;
904uintptr_t x25 = 0;
905uintptr_t x26 = 0;
906uintptr_t x27 = 0;
907uintptr_t x28 = 0;
908uintptr_t fp = 0;
909uintptr_t sp = 0;
910uintptr_t pc = 0;
911
912void handle_exception(arm_thread_state64_t *state)
913{
914 unw_cursor_t curs;
915 unw_word_t reg;
916 int err;
917 int step;
918
919 err = unw_init_local(&curs, (unw_context_t *)state);
920 testassert(!err);
921
922 step = unw_step(&curs);
923 testassert(step == UNW_STEP_SUCCESS);
924
925 err = unw_get_reg(&curs, UNW_ARM64_X19, &reg);
926 testassert(!err);
927 testassert(reg == x19);
928
929 err = unw_get_reg(&curs, UNW_ARM64_X20, &reg);
930 testassert(!err);
931 testassert(reg == x20);
932
933 err = unw_get_reg(&curs, UNW_ARM64_X21, &reg);
934 testassert(!err);
935 testassert(reg == x21);
936
937 err = unw_get_reg(&curs, UNW_ARM64_X22, &reg);
938 testassert(!err);
939 testassert(reg == x22);
940
941 err = unw_get_reg(&curs, UNW_ARM64_X23, &reg);
942 testassert(!err);
943 testassert(reg == x23);
944
945 err = unw_get_reg(&curs, UNW_ARM64_X24, &reg);
946 testassert(!err);
947 testassert(reg == x24);
948
949 err = unw_get_reg(&curs, UNW_ARM64_X25, &reg);
950 testassert(!err);
951 testassert(reg == x25);
952
953 err = unw_get_reg(&curs, UNW_ARM64_X26, &reg);
954 testassert(!err);
955 testassert(reg == x26);
956
957 err = unw_get_reg(&curs, UNW_ARM64_X27, &reg);
958 testassert(!err);
959 testassert(reg == x27);
960
961 err = unw_get_reg(&curs, UNW_ARM64_X28, &reg);
962 testassert(!err);
963 testassert(reg == x28);
964
965 err = unw_get_reg(&curs, UNW_ARM64_FP, &reg);
966 testassert(!err);
967 testassert(reg == fp);
968
969 err = unw_get_reg(&curs, UNW_ARM64_SP, &reg);
970 testassert(!err);
971 testassert(reg == sp);
972
973 err = unw_get_reg(&curs, UNW_REG_IP, &reg);
974 testassert(!err);
975 testassert(reg == pc);
976
977 // libunwind restores PC into LR and doesn't track LR
978 // err = unw_get_reg(&curs, UNW_ARM64_LR, &reg);
979 // testassert(!err);
980 // testassert(reg == lr);
981
982 // set thread state to unwound state
983 state->__x[19] = x19;
984 state->__x[20] = x20;
985 state->__x[20] = x21;
986 state->__x[22] = x22;
987 state->__x[23] = x23;
988 state->__x[24] = x24;
989 state->__x[25] = x25;
990 state->__x[26] = x26;
991 state->__x[27] = x27;
992 state->__x[28] = x28;
993 state->__fp = fp;
994 state->__lr = pc; // libunwind restores PC into LR
995 state->__sp = sp;
996 state->__pc = pc;
997
998 caught = true;
999}
1000
1001
1002void sigtrap(int sig, siginfo_t *info, void *cc)
1003{
1004 ucontext_t *uc = (ucontext_t *)cc;
1005 struct __darwin_mcontext64 *mc = (struct __darwin_mcontext64 *)uc->uc_mcontext;
1006
1007 testprintf(" handled\n");
1008
1009 testassert(sig == SIGTRAP);
1010 testassert((uintptr_t)info->si_addr == clobbered);
1011
1012 handle_exception(&mc->__ss);
1013 // handle_exception changed register state for continuation
1014}
1015
1016
1017__asm__(
1018"\n .text"
1019"\n .globl _callit"
1020"\n _callit:"
1021// save sp and return address to variables
1022"\n mov x16, sp"
1023"\n adrp x17, _sp@PAGE"
1024"\n str x16, [x17, _sp@PAGEOFF]"
1025"\n adrp x17, _pc@PAGE"
1026"\n str lr, [x17, _pc@PAGEOFF]"
1027// save other non-volatile registers to variables
1028"\n adrp x17, _x19@PAGE"
1029"\n str x19, [x17, _x19@PAGEOFF]"
1030"\n adrp x17, _x19@PAGE"
1031"\n str x20, [x17, _x20@PAGEOFF]"
1032"\n adrp x17, _x19@PAGE"
1033"\n str x21, [x17, _x21@PAGEOFF]"
1034"\n adrp x17, _x19@PAGE"
1035"\n str x22, [x17, _x22@PAGEOFF]"
1036"\n adrp x17, _x19@PAGE"
1037"\n str x23, [x17, _x23@PAGEOFF]"
1038"\n adrp x17, _x19@PAGE"
1039"\n str x24, [x17, _x24@PAGEOFF]"
1040"\n adrp x17, _x19@PAGE"
1041"\n str x25, [x17, _x25@PAGEOFF]"
1042"\n adrp x17, _x19@PAGE"
1043"\n str x26, [x17, _x26@PAGEOFF]"
1044"\n adrp x17, _x19@PAGE"
1045"\n str x27, [x17, _x27@PAGEOFF]"
1046"\n adrp x17, _x19@PAGE"
1047"\n str x28, [x17, _x28@PAGEOFF]"
1048"\n adrp x17, _x19@PAGE"
1049"\n str fp, [x17, _fp@PAGEOFF]"
1050"\n br x2"
1051 );
1052
1053
1054// arm64
1055#else
1056
1057#error unknown architecture
1058
1059#endif
1060
1061
1062insn_t set(uintptr_t dst, insn_t newvalue)
7af964d1 1063{
8070259c
A
1064 uintptr_t start = dst & ~(PAGE_MAX_SIZE-1);
1065 mprotect((void*)start, PAGE_MAX_SIZE, PROT_READ|PROT_WRITE);
1066 insn_t oldvalue = *(insn_t *)dst;
1067 *(insn_t *)dst = newvalue;
1068 mprotect((void*)start, PAGE_MAX_SIZE, PROT_READ|PROT_EXEC);
1069 return oldvalue;
1070}
1071
1072insn_t clobber(void *fn, uintptr_t offset)
1073{
1074 clobbered = (uintptr_t)fn + offset;
1075 return set((uintptr_t)fn + offset, BREAK_INSN);
1076}
1077
1078void unclobber(void *fn, uintptr_t offset, insn_t oldvalue)
1079{
1080 set((uintptr_t)fn + offset, oldvalue);
1081}
1082
1083
1084uintptr_t *getOffsets(void *symbol, const char *symname, uintptr_t *outBase)
1085{
1086 uintptr_t *result = (uintptr_t *)malloc(1000 * sizeof(uintptr_t));
1087 uintptr_t *end = result + 1000;
cd5f04f5
A
1088 uintptr_t *p = result;
1089
1090 // find library
1091 Dl_info dl;
1092 dladdr(symbol, &dl);
1093
1094 // call `otool` on library
1095 unsetenv("DYLD_LIBRARY_PATH");
1096 unsetenv("DYLD_ROOT_PATH");
1097 unsetenv("DYLD_INSERT_LIBRARIES");
8070259c
A
1098 unsetenv("DYLD_SHARED_REGION");
1099 unsetenv("DYLD_SHARED_CACHE_DIR");
1100 unsetenv("DYLD_SHARED_CACHE_DONT_VALIDATE");
cd5f04f5 1101 char *cmd;
8070259c 1102 asprintf(&cmd, OTOOL "-tv -p _%s %s",
cd5f04f5 1103 symname, dl.dli_fname);
7257e56c 1104 testprintf("%s\n", cmd);
cd5f04f5
A
1105 FILE *disa = popen(cmd, "r");
1106 free(cmd);
1107 testassert(disa);
1108
1109 // read past "_symname:" line
1110 char *line;
1111 size_t len;
1112 while ((line = fgetln(disa, &len))) {
1113 if (0 == strncmp(1+line, symname, MIN(len-1, strlen(symname)))) break;
1114 }
7af964d1 1115
cd5f04f5
A
1116 // read instructions and save offsets
1117 char op[128];
1118 long base = 0;
1119 long addr;
1120 while (2 == fscanf(disa, "%lx%s%*[^\n]\n", &addr, op)) {
1121 if (base == 0) base = addr;
1122 if (0 != strncmp(op, "nop", 3)) {
1123 testassert(p < end);
1124 *p++ = addr - base;
1125 } else {
1126 // assume nops are unreached (e.g. alignment padding)
1127 }
1128 }
1129 pclose(disa);
7af964d1 1130
8070259c
A
1131#if __arm64__
1132 // Also add breakpoints in _objc_msgSend_uncached_impcache
1133 // (which is the slow path and has a frame to unwind)
1134 if (0 != strcmp(symname, "_objc_msgSend_uncached_impcache")) {
1135 uintptr_t base2;
1136 uintptr_t *more_offsets = getOffsets(symbol, "_objc_msgSend_uncached_impcache", &base2);
1137 uintptr_t *q = more_offsets;
1138 // Skip prologue because it's imprecisely modeled in compact unwind
1139 testassert(*q != ~0UL);
1140 q++;
1141 testassert(*q != ~0UL);
1142 q++;
1143 while (*q != ~0UL) *p++ = *q++ + base2 - base;
1144 // Skip return because it's imprecisely modeled in compact unwind
1145 p--;
1146 free(more_offsets);
1147 }
1148#endif
1149
cd5f04f5
A
1150 testassert(p > result);
1151 testassert(p < end);
1152 *p = ~0UL;
8070259c 1153#if __x86_64__
7257e56c
A
1154 // hack: skip last instruction because libunwind blows up if it's
1155 // one byte long and followed by the next function with no NOPs first
8070259c
A
1156 p[-1] = ~0UL;
1157#endif
1158 if (outBase) *outBase = base;
cd5f04f5
A
1159 return result;
1160}
7af964d1 1161
8070259c
A
1162void CALLIT(void *o, void *sel_arg, SEL s, void *f, bool stret) __attribute__((noinline));
1163void CALLIT(void *o, void *sel_arg, SEL s, void *f, bool stret)
cd5f04f5
A
1164{
1165 uintptr_t message_ref[2];
1166 if (sel_arg != s) {
1167 // fixup dispatch
1168 // copy to a local buffer to keep sel_arg un-fixed-up
1169 memcpy(message_ref, sel_arg, sizeof(message_ref));
1170 sel_arg = message_ref;
1171 }
8070259c
A
1172 if (!stret) callit(o, sel_arg, f);
1173#if SUPPORT_STRET
1174 else callit_stret(o, sel_arg, f);
1175#else
1176 else fail("stret?");
1177#endif
1178}
1179
1180void test_dw_forward(void)
1181{
1182 return;
1183}
1184
1185struct stret test_dw_forward_stret(void)
1186{
1187 return zero;
cd5f04f5 1188}
7af964d1 1189
cd5f04f5
A
1190// sub = ordinary receiver object
1191// tagged = tagged receiver object
1192// SEL = selector to send
1193// sub_arg = arg to pass in receiver register (may be objc_super struct)
1194// tagged_arg = arg to pass in receiver register (may be objc_super struct)
1195// sel_arg = arg to pass in sel register (may be message_ref)
8070259c
A
1196// uncaughtAllowed is the number of acceptable unreachable instructions
1197// (for example, the ones that handle the corrupt-cache-error case)
1198void test_dw(const char *name, id sub, id tagged, bool stret,
1199 int uncaughtAllowed)
cd5f04f5 1200{
8070259c
A
1201 SEL sel = @selector(a);
1202
1203 testprintf("DWARF FOR %s%s\n", name, stret ? " (stret)" : "");
1204
1205 // We need 2 SELs of each alignment so we can generate hash collisions.
1206 // sel_registerName() never returns those alignments because they
1207 // differ from malloc's alignment. So we create lots of compiled-in
1208 // SELs here and hope something fits.
1209 SEL lotsOfSels[] = {
1210 @selector(a1), @selector(a2), @selector(a3), @selector(a4),
1211 @selector(a5), @selector(a6), @selector(a7), @selector(a8),
1212 @selector(aa), @selector(ab), @selector(ac), @selector(ad),
1213 @selector(ae), @selector(af), @selector(ag), @selector(ah),
1214 @selector(A1), @selector(A2), @selector(A3), @selector(A4),
1215 @selector(A5), @selector(A6), @selector(A7), @selector(A8),
1216 @selector(AA), @selector(Ab), @selector(Ac), @selector(Ad),
1217 @selector(Ae), @selector(Af), @selector(Ag), @selector(Ah),
1218 @selector(bb1), @selector(bb2), @selector(bb3), @selector(bb4),
1219 @selector(bb5), @selector(bb6), @selector(bb7), @selector(bb8),
1220 @selector(bba), @selector(bbb), @selector(bbc), @selector(bbd),
1221 @selector(bbe), @selector(bbf), @selector(bbg), @selector(bbh),
1222 @selector(BB1), @selector(BB2), @selector(BB3), @selector(BB4),
1223 @selector(BB5), @selector(BB6), @selector(BB7), @selector(BB8),
1224 @selector(BBa), @selector(BBb), @selector(BBc), @selector(BBd),
1225 @selector(BBe), @selector(BBf), @selector(BBg), @selector(BBh),
1226 @selector(ccc1), @selector(ccc2), @selector(ccc3), @selector(ccc4),
1227 @selector(ccc5), @selector(ccc6), @selector(ccc7), @selector(ccc8),
1228 @selector(ccca), @selector(cccb), @selector(cccc), @selector(cccd),
1229 @selector(ccce), @selector(cccf), @selector(cccg), @selector(ccch),
1230 @selector(CCC1), @selector(CCC2), @selector(CCC3), @selector(CCC4),
1231 @selector(CCC5), @selector(CCC6), @selector(CCC7), @selector(CCC8),
1232 @selector(CCCa), @selector(CCCb), @selector(CCCc), @selector(CCCd),
1233 @selector(CCCe), @selector(CCCf), @selector(CCCg), @selector(CCCh),
1234 };
1235 #define ALIGNCOUNT 16
1236 SEL sels[ALIGNCOUNT][2] = {{0}};
1237 for (int align = 0; align < ALIGNCOUNT; align++) {
1238 for (size_t i = 0; i < sizeof(lotsOfSels)/sizeof(lotsOfSels[0]); i++) {
1239 if ((uintptr_t)(void*)lotsOfSels[i] % ALIGNCOUNT == align) {
1240 if (sels[align][0]) {
1241 sels[align][1] = lotsOfSels[i];
1242 } else {
1243 sels[align][0] = lotsOfSels[i];
1244 }
1245 }
1246 }
1247 if (!sels[align][0]) fail("no SEL with alignment %d", align);
1248 if (!sels[align][1]) fail("only one SEL with alignment %d", align);
1249 }
7af964d1 1250
cd5f04f5
A
1251 void *fn = dlsym(RTLD_DEFAULT, name);
1252 testassert(fn);
7af964d1 1253
cd5f04f5 1254 // argument substitutions
7af964d1 1255
cd5f04f5
A
1256 void *sub_arg = (void*)objc_unretainedPointer(sub);
1257 void *tagged_arg = (void*)objc_unretainedPointer(tagged);
1258 void *sel_arg = (void*)sel;
7af964d1 1259
cd5f04f5
A
1260 struct objc_super sup_st = { sub, object_getClass(sub) };
1261 struct objc_super tagged_sup_st = { tagged, object_getClass(tagged) };
1262 struct { void *imp; SEL sel; } message_ref = { fn, sel };
1263
8070259c
A
1264 Class cache_cls = object_getClass(sub);
1265
cd5f04f5
A
1266 if (strstr(name, "Super")) {
1267 // super version - replace receiver with objc_super
8070259c
A
1268 // clear caches of superclass
1269 cache_cls = class_getSuperclass(cache_cls);
cd5f04f5
A
1270 sub_arg = &sup_st;
1271 tagged_arg = &tagged_sup_st;
1272 }
1273
1274 if (strstr(name, "_fixup")) {
1275 // fixup version - replace sel with message_ref
1276 sel_arg = &message_ref;
1277 }
1278
1279
8070259c 1280 uintptr_t *insnOffsets = getOffsets(fn, name, nil);
cd5f04f5 1281 uintptr_t offset;
8070259c
A
1282 int uncaughtCount = 0;
1283 for (int oo = 0; insnOffsets[oo] != ~0UL; oo++) {
1284 offset = insnOffsets[oo];
cd5f04f5
A
1285 testprintf("OFFSET %lu\n", offset);
1286
8070259c 1287 insn_t saved_insn = clobber(fn, offset);
cd5f04f5
A
1288 caught = false;
1289
1290 // nil
1291 if ((void*)objc_unretainedPointer(sub) == sub_arg) {
1292 SELF = nil;
1293 testprintf(" nil\n");
8070259c
A
1294 CALLIT(nil, sel_arg, sel, fn, stret);
1295 CALLIT(nil, sel_arg, sel, fn, stret);
cd5f04f5
A
1296 }
1297
1298 // uncached
1299 SELF = sub;
1300 testprintf(" uncached\n");
8070259c
A
1301 _objc_flush_caches(cache_cls);
1302 CALLIT(sub_arg, sel_arg, sel, fn, stret);
1303 _objc_flush_caches(cache_cls);
1304 CALLIT(sub_arg, sel_arg, sel, fn, stret);
cd5f04f5
A
1305
1306 // cached
1307 SELF = sub;
1308 testprintf(" cached\n");
8070259c
A
1309 CALLIT(sub_arg, sel_arg, sel, fn, stret);
1310 CALLIT(sub_arg, sel_arg, sel, fn, stret);
cd5f04f5
A
1311
1312 // uncached,tagged
1313 SELF = tagged;
1314 testprintf(" uncached,tagged\n");
8070259c
A
1315 _objc_flush_caches(cache_cls);
1316 CALLIT(tagged_arg, sel_arg, sel, fn, stret);
1317 _objc_flush_caches(cache_cls);
1318 CALLIT(tagged_arg, sel_arg, sel, fn, stret);
cd5f04f5
A
1319
1320 // cached,tagged
1321 SELF = tagged;
1322 testprintf(" cached,tagged\n");
8070259c
A
1323 CALLIT(tagged_arg, sel_arg, sel, fn, stret);
1324 CALLIT(tagged_arg, sel_arg, sel, fn, stret);
1325
1326 // multiple SEL alignments, collisions, wraps
1327 SELF = sub;
1328 for (int a = 0; a < ALIGNCOUNT; a++) {
1329 testprintf(" cached, SEL alignment %d\n", a);
1330
1331 // Count both up and down to be independent of
1332 // implementation's cache scan direction
1333
1334 _objc_flush_caches(cache_cls);
1335 for (int x2 = 0; x2 < 1; x2++) {
1336 for (int s = 0; s < 4; s++) {
1337 int align = (a+s) % ALIGNCOUNT;
1338 CALLIT(sub_arg, sels[align][0], sels[align][0], fn, stret);
1339 CALLIT(sub_arg, sels[align][1], sels[align][1], fn, stret);
1340 }
1341 }
1342
1343 _objc_flush_caches(cache_cls);
1344 for (int x2 = 0; x2 < 1; x2++) {
1345 for (int s = 0; s < 4; s++) {
1346 int align = abs(a-s) % ALIGNCOUNT;
1347 CALLIT(sub_arg, sels[align][0], sels[align][0], fn, stret);
1348 CALLIT(sub_arg, sels[align][1], sels[align][1], fn, stret);
1349 }
1350 }
1351 }
cd5f04f5 1352
8070259c
A
1353 unclobber(fn, offset, saved_insn);
1354
1355 // remember offsets that were caught by none of the above
1356 if (caught) {
1357 insnOffsets[oo] = 0;
1358 } else {
1359 uncaughtCount++;
1360 testprintf("offset %s+%lu not caught (%d/%d)\n",
1361 name, offset, uncaughtCount, uncaughtAllowed);
1362 }
1363 }
cd5f04f5 1364
8070259c
A
1365 // Complain if too many offsets went uncaught.
1366 // Acceptably-uncaught offsets include the corrupt-cache-error handler.
1367 if (uncaughtCount != uncaughtAllowed) {
1368 for (int oo = 0; insnOffsets[oo] != ~0UL; oo++) {
1369 if (insnOffsets[oo]) {
1370 fprintf(stderr, "BAD: offset %s+%lu not caught\n",
1371 name, insnOffsets[oo]);
1372 }
1373 }
1374 fail("wrong instructions not reached for %s (missed %d, expected %d)",
1375 name, uncaughtCount, uncaughtAllowed);
cd5f04f5 1376 }
8070259c 1377
cd5f04f5
A
1378 free(insnOffsets);
1379}
1380
8070259c
A
1381
1382// TEST_DWARF
cd5f04f5
A
1383#endif
1384
1385
1386void test_basic(id receiver)
1387{
1388 id idval;
1389 long long llval;
1390 struct stret stretval;
1391 double fpval;
1392 long double lfpval;
7af964d1
A
1393
1394 // message uncached
1395 // message uncached long long
1396 // message uncached stret
1397 // message uncached fpret
1398 // message uncached fpret long double
8972963c 1399 // message uncached noarg (as above)
7af964d1
A
1400 // message cached
1401 // message cached long long
1402 // message cached stret
1403 // message cached fpret
1404 // message cached fpret long double
8972963c 1405 // message cached noarg (as above)
7af964d1 1406 // fixme verify that uncached lookup didn't happen the 2nd time?
cd5f04f5
A
1407 SELF = receiver;
1408 for (int i = 0; i < 5; i++) {
8070259c 1409 testprintf("idret\n");
7af964d1
A
1410 state = 0;
1411 idval = nil;
cd5f04f5 1412 idval = [receiver idret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
8972963c 1413 testassert(state == 101);
7af964d1
A
1414 testassert(idval == ID_RESULT);
1415
8070259c 1416 testprintf("llret\n");
7af964d1 1417 llval = 0;
cd5f04f5 1418 llval = [receiver llret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
8972963c 1419 testassert(state == 102);
7af964d1
A
1420 testassert(llval == LL_RESULT);
1421
8070259c 1422 testprintf("stret\n");
7af964d1 1423 stretval = zero;
cd5f04f5 1424 stretval = [receiver stret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
8972963c 1425 testassert(state == 103);
7af964d1
A
1426 testassert(stret_equal(stretval, STRET_RESULT));
1427
8070259c 1428 testprintf("fpret\n");
7af964d1 1429 fpval = 0;
cd5f04f5 1430 fpval = [receiver fpret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
8972963c 1431 testassert(state == 104);
7af964d1
A
1432 testassert(fpval == FP_RESULT);
1433
8070259c 1434 testprintf("lfpret\n");
7af964d1 1435 lfpval = 0;
cd5f04f5 1436 lfpval = [receiver lfpret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
8972963c 1437 testassert(state == 105);
7af964d1 1438 testassert(lfpval == LFP_RESULT);
8972963c
A
1439
1440#if __OBJC2__
1441 // explicitly call noarg messenger, even if compiler doesn't emit it
1442 state = 0;
8070259c 1443 testprintf("idret noarg\n");
8972963c 1444 idval = nil;
cd5f04f5 1445 idval = ((typeof(idmsg0))objc_msgSend_noarg)(receiver, @selector(idret_noarg));
8972963c
A
1446 testassert(state == 111);
1447 testassert(idval == ID_RESULT);
1448
1449 llval = 0;
8070259c 1450 testprintf("llret noarg\n");
cd5f04f5 1451 llval = ((typeof(llmsg0))objc_msgSend_noarg)(receiver, @selector(llret_noarg));
8972963c
A
1452 testassert(state == 112);
1453 testassert(llval == LL_RESULT);
1454 /*
cd5f04f5 1455 no objc_msgSend_stret_noarg
8972963c 1456 stretval = zero;
cd5f04f5
A
1457 stretval = ((typeof(stretmsg0))objc_msgSend_stret_noarg)(receiver, @selector(stret_noarg));
1458 stretval = [receiver stret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
8972963c
A
1459 testassert(state == 113);
1460 testassert(stret_equal(stretval, STRET_RESULT));
1461 */
1462# if !__i386__
8070259c 1463 testprintf("fpret noarg\n");
8972963c 1464 fpval = 0;
cd5f04f5 1465 fpval = ((typeof(fpmsg0))objc_msgSend_noarg)(receiver, @selector(fpret_noarg));
8972963c
A
1466 testassert(state == 114);
1467 testassert(fpval == FP_RESULT);
1468# endif
1469# if !__i386__ && !__x86_64__
8070259c 1470 testprintf("lfpret noarg\n");
8972963c 1471 lfpval = 0;
cd5f04f5 1472 lfpval = ((typeof(lfpmsg0))objc_msgSend_noarg)(receiver, @selector(lfpret_noarg));
8972963c
A
1473 testassert(state == 115);
1474 testassert(lfpval == LFP_RESULT);
1475# endif
1476#endif
7af964d1 1477 }
8070259c
A
1478
1479 testprintf("basic done\n");
cd5f04f5
A
1480}
1481
1482int main()
1483{
1484 PUSH_POOL {
1485 int i;
1486
1487 id idval;
1488 long long llval;
1489 struct stret stretval;
1490 double fpval;
1491 long double lfpval;
1492
7257e56c
A
1493#if __x86_64__
1494 struct stret *stretptr;
1495#endif
1496
cd5f04f5
A
1497 uint64_t startTime;
1498 uint64_t totalTime;
1499 uint64_t targetTime;
1500
1501 Method idmethod;
1502 Method llmethod;
1503 Method stretmethod;
1504 Method fpmethod;
1505 Method lfpmethod;
1506
1507 id (*idfn)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double);
1508 long long (*llfn)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double);
1509 struct stret (*stretfn)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double);
1510 double (*fpfn)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double);
1511 long double (*lfpfn)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double);
1512
1513 id (*idmsg)(id, SEL, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double) __attribute__((unused));
1514 id (*idmsgsuper)(struct objc_super *, SEL, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double) __attribute__((unused));
1515 long long (*llmsg)(id, SEL, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double) __attribute__((unused));
1516 struct stret (*stretmsg)(id, SEL, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double) __attribute__((unused));
1517 struct stret (*stretmsgsuper)(struct objc_super *, SEL, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double) __attribute__((unused));
1518 double (*fpmsg)(id, SEL, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double) __attribute__((unused));
1519 long double (*lfpmsg)(id, SEL, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double) __attribute__((unused));
1520
1521 // get +initialize out of the way
1522 [Sub class];
7257e56c 1523#if OBJC_HAVE_TAGGED_POINTERS
cd5f04f5
A
1524 [TaggedSub class];
1525#endif
1526
1527 ID_RESULT = [Super new];
7af964d1 1528
cd5f04f5
A
1529 Sub *sub = [Sub new];
1530 Super *sup = [Super new];
7257e56c
A
1531#if OBJC_HAVE_TAGGED_POINTERS
1532 TaggedSub *tagged = objc_unretainedObject(_objc_makeTaggedPointer(OBJC_TAG_7, 999));
cd5f04f5 1533#endif
7257e56c 1534
cd5f04f5
A
1535 // Basic cached and uncached dispatch.
1536 // Do this first before anything below caches stuff.
7257e56c 1537 testprintf("basic\n");
cd5f04f5 1538 test_basic(sub);
7257e56c
A
1539#if OBJC_HAVE_TAGGED_POINTERS
1540 testprintf("basic tagged\n");
cd5f04f5
A
1541 test_basic(tagged);
1542#endif
1543
1544 idmethod = class_getInstanceMethod([Super class], @selector(idret::::::::::::::::::::::::::::));
8972963c 1545 testassert(idmethod);
cd5f04f5 1546 llmethod = class_getInstanceMethod([Super class], @selector(llret::::::::::::::::::::::::::::));
8972963c 1547 testassert(llmethod);
cd5f04f5 1548 stretmethod = class_getInstanceMethod([Super class], @selector(stret::::::::::::::::::::::::::::));
8972963c 1549 testassert(stretmethod);
cd5f04f5 1550 fpmethod = class_getInstanceMethod([Super class], @selector(fpret::::::::::::::::::::::::::::));
8972963c 1551 testassert(fpmethod);
cd5f04f5 1552 lfpmethod = class_getInstanceMethod([Super class], @selector(lfpret::::::::::::::::::::::::::::));
8972963c
A
1553 testassert(lfpmethod);
1554
1555 idfn = (id (*)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double)) method_invoke;
1556 llfn = (long long (*)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double)) method_invoke;
1557 stretfn = (struct stret (*)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double)) method_invoke_stret;
1558 fpfn = (double (*)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double)) method_invoke;
1559 lfpfn = (long double (*)(id, Method, int, int, int, int, int, int, int, int, int, int, int, int, int, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double)) method_invoke;
1560
7af964d1
A
1561 // cached message performance
1562 // catches failure to cache or (abi=2) failure to fixup (#5584187)
1563 // fixme unless they all fail
1564 // `.align 4` matches loop alignment to make -O0 work
8972963c 1565 // fill cache first
7257e56c
A
1566 testprintf("time checks\n");
1567
cd5f04f5
A
1568 SELF = sub;
1569 [sub voidret_nop];
8070259c 1570 [sub voidret_nop2];
cd5f04f5
A
1571 [sub llret_nop];
1572 [sub stret_nop];
1573 [sub fpret_nop];
1574 [sub lfpret_nop];
1575 [sub voidret_nop];
8070259c 1576 [sub voidret_nop2];
cd5f04f5
A
1577 [sub llret_nop];
1578 [sub stret_nop];
1579 [sub fpret_nop];
1580 [sub lfpret_nop];
1581 [sub voidret_nop];
8070259c 1582 [sub voidret_nop2];
cd5f04f5
A
1583 [sub llret_nop];
1584 [sub stret_nop];
1585 [sub fpret_nop];
1586 [sub lfpret_nop];
8972963c
A
1587
1588 // Some of these times have high variance on some compilers.
1589 // The errors we're trying to catch should be catastrophically slow,
1590 // so the margins here are generous to avoid false failures.
1591
8070259c
A
1592 // Use voidret because id return is too slow for perf test with ARC.
1593
1594 // Pick smallest of voidret_nop and voidret_nop2 time
1595 // in the hopes that one of them didn't collide in the method cache.
1596
8972963c 1597#define COUNT 1000000
8070259c 1598
7af964d1 1599 startTime = mach_absolute_time();
8972963c 1600 ALIGN_();
7af964d1 1601 for (i = 0; i < COUNT; i++) {
8070259c 1602 [sub voidret_nop];
cd5f04f5
A
1603 }
1604 totalTime = mach_absolute_time() - startTime;
8070259c 1605 testprintf("time: voidret %llu\n", totalTime);
cd5f04f5
A
1606 targetTime = totalTime;
1607
1608 startTime = mach_absolute_time();
1609 ALIGN_();
1610 for (i = 0; i < COUNT; i++) {
8070259c 1611 [sub voidret_nop2];
7af964d1
A
1612 }
1613 totalTime = mach_absolute_time() - startTime;
8070259c
A
1614 testprintf("time: voidret2 %llu\n", totalTime);
1615 if (totalTime < targetTime) targetTime = totalTime;
7af964d1 1616
7af964d1 1617 startTime = mach_absolute_time();
8972963c 1618 ALIGN_();
7af964d1 1619 for (i = 0; i < COUNT; i++) {
cd5f04f5 1620 [sub llret_nop];
7af964d1
A
1621 }
1622 totalTime = mach_absolute_time() - startTime;
cd5f04f5 1623 timecheck("llret ", totalTime, targetTime * 0.7, targetTime * 2.0);
8972963c 1624
7af964d1 1625 startTime = mach_absolute_time();
8972963c 1626 ALIGN_();
7af964d1 1627 for (i = 0; i < COUNT; i++) {
cd5f04f5 1628 [sub stret_nop];
7af964d1
A
1629 }
1630 totalTime = mach_absolute_time() - startTime;
cd5f04f5 1631 timecheck("stret ", totalTime, targetTime * 0.7, targetTime * 5.0);
7af964d1 1632
7af964d1 1633 startTime = mach_absolute_time();
8972963c 1634 ALIGN_();
7af964d1 1635 for (i = 0; i < COUNT; i++) {
cd5f04f5 1636 [sub fpret_nop];
7af964d1
A
1637 }
1638 totalTime = mach_absolute_time() - startTime;
cd5f04f5 1639 timecheck("fpret ", totalTime, targetTime * 0.7, targetTime * 4.0);
7af964d1 1640
7af964d1 1641 startTime = mach_absolute_time();
8972963c 1642 ALIGN_();
7af964d1 1643 for (i = 0; i < COUNT; i++) {
cd5f04f5 1644 [sub lfpret_nop];
7af964d1
A
1645 }
1646 totalTime = mach_absolute_time() - startTime;
cd5f04f5 1647 timecheck("lfpret", totalTime, targetTime * 0.7, targetTime * 4.0);
8070259c
A
1648
1649#if __arm64__
1650 // Removing this testwarn(), or changing voidret_nop to nop;ret,
1651 // changes the voidret_nop and stret_nop times above by a factor of 2.
1652 testwarn("rdar://13896922 nop;ret is faster than ret?");
1653#endif
1654
7af964d1
A
1655#undef COUNT
1656
1657 // method_invoke
1658 // method_invoke long long
1659 // method_invoke_stret stret
1660 // method_invoke_stret fpret
1661 // method_invoke fpret long double
7257e56c
A
1662 testprintf("method_invoke\n");
1663
cd5f04f5 1664 SELF = sup;
7af964d1
A
1665
1666 state = 0;
1667 idval = nil;
cd5f04f5 1668 idval = (*idfn)(sup, idmethod, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0);
7af964d1
A
1669 testassert(state == 1);
1670 testassert(idval == ID_RESULT);
1671
1672 llval = 0;
cd5f04f5 1673 llval = (*llfn)(sup, llmethod, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0);
7af964d1
A
1674 testassert(state == 2);
1675 testassert(llval == LL_RESULT);
1676
1677 stretval = zero;
cd5f04f5 1678 stretval = (*stretfn)(sup, stretmethod, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0);
7af964d1
A
1679 testassert(state == 3);
1680 testassert(stret_equal(stretval, STRET_RESULT));
1681
1682 fpval = 0;
cd5f04f5 1683 fpval = (*fpfn)(sup, fpmethod, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0);
7af964d1
A
1684 testassert(state == 4);
1685 testassert(fpval == FP_RESULT);
1686
1687 lfpval = 0;
cd5f04f5 1688 lfpval = (*lfpfn)(sup, lfpmethod, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0);
7af964d1
A
1689 testassert(state == 5);
1690 testassert(lfpval == LFP_RESULT);
1691
1692
1693 // message to nil
1694 // message to nil long long
1695 // message to nil stret
1696 // message to nil fpret
1697 // message to nil fpret long double
7257e56c
A
1698 // Use NIL_RECEIVER to avoid compiler optimizations.
1699 testprintf("message to nil\n");
1700
7af964d1
A
1701 state = 0;
1702 idval = ID_RESULT;
7257e56c 1703 idval = [(id)NIL_RECEIVER idret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
7af964d1
A
1704 testassert(state == 0);
1705 testassert(idval == nil);
1706
1707 state = 0;
1708 llval = LL_RESULT;
7257e56c 1709 llval = [(id)NIL_RECEIVER llret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
7af964d1
A
1710 testassert(state == 0);
1711 testassert(llval == 0LL);
1712
1713 state = 0;
1714 stretval = zero;
7257e56c 1715 stretval = [(id)NIL_RECEIVER stret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
7af964d1 1716 testassert(state == 0);
cd5f04f5
A
1717#if __clang__
1718 testassert(0 == memcmp(&stretval, &zero, sizeof(stretval)));
1719#else
7af964d1 1720 // no stret result guarantee
cd5f04f5 1721#endif
7257e56c
A
1722
1723#if __x86_64__
1724 // check stret return register
1725 state = 0;
1726 stretval = zero;
1727 stretptr = ((struct stret *(*)(struct stret *, id, SEL))objc_msgSend_stret)
1728 (&stretval, nil, @selector(stret_nop));
1729 testassert(stretptr == &stretval);
1730 testassert(state == 0);
1731 // no stret result guarantee for hand-written calls, even with clang
1732#endif
1733
8070259c
A
1734#if __i386__
1735 // check struct-return address stack pop
1736 for (int i = 0; i < 10000000; i++) {
1737 state = 0;
1738 ((struct stret (*)(id, SEL))objc_msgSend_stret)
1739 (nil, @selector(stret_nop));
1740 }
1741#endif
1742
7af964d1
A
1743 state = 0;
1744 fpval = FP_RESULT;
7257e56c 1745 fpval = [(id)NIL_RECEIVER fpret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
7af964d1
A
1746 testassert(state == 0);
1747 testassert(fpval == 0.0);
1748
1749 state = 0;
1750 lfpval = LFP_RESULT;
7257e56c 1751 lfpval = [(id)NIL_RECEIVER lfpret :1:2:3:4:5:6:7:8:9:10:11:12:13:1.0:2.0:3.0:4.0:5.0:6.0:7.0:8.0:9.0:10.0:11.0:12.0:13.0:14.0:15.0];
7af964d1
A
1752 testassert(state == 0);
1753 testassert(lfpval == 0.0);
8972963c 1754
8070259c
A
1755 // message to nil, different struct types
1756 // This verifies that ordinary objc_msgSend() erases enough registers
1757 // for structs that return in registers.
1758#define TEST_NIL_STRUCT(i,n) \
1759 do { \
1760 struct stret_##i##n z; \
1761 bzero(&z, sizeof(z)); \
1762 [Super stret_i##n##_nonzero]; \
1763 [Super stret_d##n##_nonzero]; \
1764 struct stret_##i##n val = [(id)NIL_RECEIVER stret_##i##n##_zero]; \
1765 testassert(0 == memcmp(&z, &val, sizeof(val))); \
1766 } while (0)
1767
1768 TEST_NIL_STRUCT(i,1);
1769 TEST_NIL_STRUCT(i,2);
1770 TEST_NIL_STRUCT(i,3);
1771 TEST_NIL_STRUCT(i,4);
1772 TEST_NIL_STRUCT(i,5);
1773 TEST_NIL_STRUCT(i,6);
1774 TEST_NIL_STRUCT(i,7);
1775 TEST_NIL_STRUCT(i,8);
1776 TEST_NIL_STRUCT(i,9);
1777
1778#if __i386__
1779 testwarn("rdar://16267205 i386 struct{float} and struct{double}");
1780#else
1781 TEST_NIL_STRUCT(d,1);
1782#endif
1783 TEST_NIL_STRUCT(d,2);
1784 TEST_NIL_STRUCT(d,3);
1785 TEST_NIL_STRUCT(d,4);
1786 TEST_NIL_STRUCT(d,5);
1787 TEST_NIL_STRUCT(d,6);
1788 TEST_NIL_STRUCT(d,7);
1789 TEST_NIL_STRUCT(d,8);
1790 TEST_NIL_STRUCT(d,9);
1791
1792
cd5f04f5 1793#if __OBJC2__
8972963c
A
1794 // message to nil noarg
1795 // explicitly call noarg messenger, even if compiler doesn't emit it
1796 state = 0;
1797 idval = ID_RESULT;
1798 idval = ((typeof(idmsg0))objc_msgSend_noarg)(nil, @selector(idret_noarg));
1799 testassert(state == 0);
1800 testassert(idval == nil);
7af964d1 1801
8972963c
A
1802 state = 0;
1803 llval = LL_RESULT;
1804 llval = ((typeof(llmsg0))objc_msgSend_noarg)(nil, @selector(llret_noarg));
1805 testassert(state == 0);
1806 testassert(llval == 0LL);
cd5f04f5
A
1807
1808 // no stret_noarg messenger
1809
8972963c
A
1810# if !__i386__
1811 state = 0;
1812 fpval = FP_RESULT;
1813 fpval = ((typeof(fpmsg0))objc_msgSend_noarg)(nil, @selector(fpret_noarg));
1814 testassert(state == 0);
1815 testassert(fpval == 0.0);
1816# endif
1817# if !__i386__ && !__x86_64__
1818 state = 0;
1819 lfpval = LFP_RESULT;
1820 lfpval = ((typeof(lfpmsg0))objc_msgSend_noarg)(nil, @selector(lfpret_noarg));
1821 testassert(state == 0);
1822 testassert(lfpval == 0.0);
1823# endif
1824#endif
7257e56c 1825
7af964d1 1826
8972963c
A
1827#if __OBJC2__
1828 // rdar://8271364 objc_msgSendSuper2 must not change objc_super
7257e56c 1829 testprintf("super struct\n");
cd5f04f5
A
1830 struct objc_super sup_st = {
1831 sub,
1832 object_getClass(sub),
8972963c
A
1833 };
1834
cd5f04f5
A
1835 SELF = sub;
1836
8972963c
A
1837 state = 100;
1838 idval = nil;
cd5f04f5 1839 idval = ((id(*)(struct objc_super *, SEL, int,int,int,int,int,int,int,int,int,int,int,int,int, double,double,double,double,double,double,double,double,double,double,double,double,double,double,double))objc_msgSendSuper2) (&sup_st, @selector(idret::::::::::::::::::::::::::::), 1,2,3,4,5,6,7,8,9,10,11,12,13, 1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0);
8972963c
A
1840 testassert(state == 1);
1841 testassert(idval == ID_RESULT);
cd5f04f5
A
1842 testassert(sup_st.receiver == sub);
1843 testassert(sup_st.super_class == object_getClass(sub));
8972963c
A
1844
1845 state = 100;
1846 stretval = zero;
cd5f04f5 1847 stretval = ((struct stret(*)(struct objc_super *, SEL, int,int,int,int,int,int,int,int,int,int,int,int,int, double,double,double,double,double,double,double,double,double,double,double,double,double,double,double))objc_msgSendSuper2_stret) (&sup_st, @selector(stret::::::::::::::::::::::::::::), 1,2,3,4,5,6,7,8,9,10,11,12,13, 1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0);
8972963c
A
1848 testassert(state == 3);
1849 testassert(stret_equal(stretval, STRET_RESULT));
cd5f04f5
A
1850 testassert(sup_st.receiver == sub);
1851 testassert(sup_st.super_class == object_getClass(sub));
8972963c
A
1852#endif
1853
8070259c 1854#if __OBJC2__ && !__arm64__
8972963c 1855 // Debug messengers.
7257e56c
A
1856 testprintf("debug messengers\n");
1857
8972963c
A
1858 state = 0;
1859 idmsg = (typeof(idmsg))objc_msgSend_debug;
1860 idval = nil;
cd5f04f5 1861 idval = (*idmsg)(sub, @selector(idret::::::::::::::::::::::::::::), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0);
8972963c
A
1862 testassert(state == 101);
1863 testassert(idval == ID_RESULT);
1864
1865 state = 0;
1866 llmsg = (typeof(llmsg))objc_msgSend_debug;
1867 llval = 0;
cd5f04f5 1868 llval = (*llmsg)(sub, @selector(llret::::::::::::::::::::::::::::), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0);
8972963c
A
1869 testassert(state == 102);
1870 testassert(llval == LL_RESULT);
1871
1872 state = 0;
1873 stretmsg = (typeof(stretmsg))objc_msgSend_stret_debug;
1874 stretval = zero;
cd5f04f5 1875 stretval = (*stretmsg)(sub, @selector(stret::::::::::::::::::::::::::::), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0);
8972963c
A
1876 testassert(state == 103);
1877 testassert(stret_equal(stretval, STRET_RESULT));
1878
1879 state = 100;
cd5f04f5
A
1880 sup_st.receiver = sub;
1881 sup_st.super_class = object_getClass(sub);
1882 idmsgsuper = (typeof(idmsgsuper))objc_msgSendSuper2_debug;
8972963c 1883 idval = nil;
cd5f04f5 1884 idval = (*idmsgsuper)(&sup_st, @selector(idret::::::::::::::::::::::::::::), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0);
8972963c
A
1885 testassert(state == 1);
1886 testassert(idval == ID_RESULT);
1887
1888 state = 100;
cd5f04f5
A
1889 sup_st.receiver = sub;
1890 sup_st.super_class = object_getClass(sub);
1891 stretmsgsuper = (typeof(stretmsgsuper))objc_msgSendSuper2_stret_debug;
8972963c 1892 stretval = zero;
cd5f04f5 1893 stretval = (*stretmsgsuper)(&sup_st, @selector(stret::::::::::::::::::::::::::::), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0);
8972963c
A
1894 testassert(state == 3);
1895 testassert(stret_equal(stretval, STRET_RESULT));
1896
1897#if __i386__
1898 state = 0;
1899 fpmsg = (typeof(fpmsg))objc_msgSend_fpret_debug;
1900 fpval = 0;
cd5f04f5 1901 fpval = (*fpmsg)(sub, @selector(fpret::::::::::::::::::::::::::::), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0);
8972963c
A
1902 testassert(state == 104);
1903 testassert(fpval == FP_RESULT);
1904#endif
1905#if __x86_64__
1906 state = 0;
1907 lfpmsg = (typeof(lfpmsg))objc_msgSend_fpret_debug;
1908 lfpval = 0;
cd5f04f5 1909 lfpval = (*lfpmsg)(sub, @selector(lfpret::::::::::::::::::::::::::::), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0);
8972963c
A
1910 testassert(state == 105);
1911 testassert(lfpval == LFP_RESULT);
1912
1913 // fixme fp2ret
1914#endif
1915
1916// debug messengers
1917#endif
1918
cd5f04f5 1919
8070259c
A
1920#if !TEST_DWARF
1921 testwarn("no unwind tables in this configuration");
1922#else
cd5f04f5 1923 // DWARF unwind tables
7257e56c 1924 testprintf("unwind tables\n");
cd5f04f5
A
1925
1926 // install exception handler
1927 struct sigaction act;
1928 act.sa_sigaction = sigtrap;
1929 act.sa_mask = 0;
1930 act.sa_flags = SA_SIGINFO;
1931 sigaction(SIGTRAP, &act, NULL);
1932
8070259c
A
1933 SubDW *dw = [[SubDW alloc] init];
1934
1935 objc_setForwardHandler((void*)test_dw_forward, (void*)test_dw_forward_stret);
1936
1937# if __x86_64__
1938 test_dw("objc_msgSend", dw, tagged, false, 2);
1939 test_dw("objc_msgSend_stret", dw, tagged, true, 4);
1940 test_dw("objc_msgSend_fpret", dw, tagged, false, 2);
1941 test_dw("objc_msgSend_fp2ret", dw, tagged, false, 2);
1942 test_dw("objc_msgSendSuper", dw, tagged, false, 2);
1943 test_dw("objc_msgSendSuper2", dw, tagged, false, 2);
1944 test_dw("objc_msgSendSuper_stret", dw, tagged, true, 4);
1945 test_dw("objc_msgSendSuper2_stret", dw, tagged, true, 4);
1946# elif __i386__
1947 test_dw("objc_msgSend", dw, dw, false, 10);
1948 test_dw("objc_msgSend_stret", dw, dw, true, 10);
1949 test_dw("objc_msgSend_fpret", dw, dw, false, 10);
1950 test_dw("objc_msgSendSuper", dw, dw, false, 10);
1951 test_dw("objc_msgSendSuper2", dw, dw, false, 10);
1952 test_dw("objc_msgSendSuper_stret", dw, dw, true, 10);
1953 test_dw("objc_msgSendSuper2_stret", dw, dw, true, 10);
1954# elif __arm64__
1955 test_dw("objc_msgSend", dw, tagged, false, 2);
1956 test_dw("objc_msgSendSuper", dw, tagged, false, 2);
1957 test_dw("objc_msgSendSuper2", dw, tagged, false, 2);
1958# else
1959# error unknown architecture
1960# endif
cd5f04f5
A
1961
1962 // DWARF unwind tables
1963#endif
8070259c 1964
cd5f04f5 1965 } POP_POOL;
7af964d1
A
1966 succeed(__FILE__);
1967}
8972963c
A
1968
1969#endif