]> git.saurik.com Git - apple/objc4.git/blob - test/msgSend.m
833f53f76fc53162b1656256e77ad540ed8437e8
[apple/objc4.git] / test / msgSend.m
1 // TEST_CFLAGS -Wno-unused-parameter
2
3 #include "test.h"
4 #include "testroot.i"
5
6 #if __cplusplus && !__clang__
7
8 int main()
9 {
10 // llvm-g++ is confused by @selector(foo::) and will never be fixed
11 succeed(__FILE__);
12 }
13
14 #else
15
16 #include <objc/objc.h>
17 #include <objc/runtime.h>
18 #include <objc/objc-internal.h>
19 #include <objc/objc-abi.h>
20
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
34 #if defined(__arm__)
35 // rdar://8331406
36 # define ALIGN_()
37 #else
38 # define ALIGN_() asm(".align 4");
39 #endif
40
41 @interface Super : TestRoot @end
42
43 @interface Sub : Super @end
44
45 static int state = 0;
46
47 static id SELF;
48
49 // for typeof() shorthand only
50 id (*idmsg0)(id, SEL) __attribute__((unused));
51 long long (*llmsg0)(id, SEL) __attribute__((unused));
52 // struct stret (*stretmsg0)(id, SEL) __attribute__((unused));
53 double (*fpmsg0)(id, SEL) __attribute__((unused));
54 long double (*lfpmsg0)(id, SEL) __attribute__((unused));
55
56
57 #define CHECK_ARGS(sel) \
58 do { \
59 testassert(self == SELF); \
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
91 #define CHECK_ARGS_NOARG(sel) \
92 do { \
93 testassert(self == SELF); \
94 testassert(_cmd == sel_registerName(#sel "_noarg"));\
95 } while (0)
96
97 id NIL_RECEIVER;
98 id ID_RESULT;
99 long long LL_RESULT = __LONG_LONG_MAX__ - 2LL*__INT_MAX__;
100 double FP_RESULT = __DBL_MIN__ + __DBL_EPSILON__;
101 long double LFP_RESULT = __LDBL_MIN__ + __LDBL_EPSILON__;
102 // STRET_RESULT in test.h
103
104 static struct stret zero;
105
106 struct stret_i1 {
107 uintptr_t i1;
108 };
109 struct stret_i2 {
110 uintptr_t i1;
111 uintptr_t i2;
112 };
113 struct stret_i3 {
114 uintptr_t i1;
115 uintptr_t i2;
116 uintptr_t i3;
117 };
118 struct stret_i4 {
119 uintptr_t i1;
120 uintptr_t i2;
121 uintptr_t i3;
122 };
123 struct stret_i5 {
124 uintptr_t i1;
125 uintptr_t i2;
126 uintptr_t i3;
127 uintptr_t i4;
128 uintptr_t i5;
129 };
130 struct 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 };
138 struct 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 };
147 struct 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 };
156 struct 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
168 struct stret_d1 {
169 double d1;
170 };
171 struct stret_d2 {
172 double d1;
173 double d2;
174 };
175 struct stret_d3 {
176 double d1;
177 double d2;
178 double d3;
179 };
180 struct stret_d4 {
181 double d1;
182 double d2;
183 double d3;
184 };
185 struct stret_d5 {
186 double d1;
187 double d2;
188 double d3;
189 double d4;
190 double d5;
191 };
192 struct stret_d6 {
193 double d1;
194 double d2;
195 double d3;
196 double d4;
197 double d5;
198 double d6;
199 };
200 struct stret_d7 {
201 double d1;
202 double d2;
203 double d3;
204 double d4;
205 double d5;
206 double d6;
207 double d7;
208 };
209 struct stret_d8 {
210 double d1;
211 double d2;
212 double d3;
213 double d4;
214 double d5;
215 double d8;
216 double d9;
217 };
218 struct 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
230
231 @implementation Super
232 -(struct stret)stret { return STRET_RESULT; }
233
234 -(id)idret:
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
236 {
237 CHECK_ARGS(idret);
238 state = 1;
239 return ID_RESULT;
240 }
241
242 -(long long)llret:
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
244 {
245 CHECK_ARGS(llret);
246 state = 2;
247 return LL_RESULT;
248 }
249
250 -(struct stret)stret:
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
252 {
253 CHECK_ARGS(stret);
254 state = 3;
255 return STRET_RESULT;
256 }
257
258 -(double)fpret:
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
260 {
261 CHECK_ARGS(fpret);
262 state = 4;
263 return FP_RESULT;
264 }
265
266 -(long double)lfpret:
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
268 {
269 CHECK_ARGS(lfpret);
270 state = 5;
271 return LFP_RESULT;
272 }
273
274
275 -(id)idret_noarg
276 {
277 CHECK_ARGS_NOARG(idret);
278 state = 11;
279 return ID_RESULT;
280 }
281
282 -(long long)llret_noarg
283 {
284 CHECK_ARGS_NOARG(llret);
285 state = 12;
286 return LL_RESULT;
287 }
288
289 -(struct stret)stret_noarg
290 {
291 CHECK_ARGS_NOARG(stret);
292 state = 13;
293 return STRET_RESULT;
294 }
295
296 -(double)fpret_noarg
297 {
298 CHECK_ARGS_NOARG(fpret);
299 state = 14;
300 return FP_RESULT;
301 }
302
303 -(long double)lfpret_noarg
304 {
305 CHECK_ARGS_NOARG(lfpret);
306 state = 15;
307 return LFP_RESULT;
308 }
309
310
311 -(void)voidret_nop
312 {
313 return;
314 }
315
316 -(void)voidret_nop2
317 {
318 return;
319 }
320
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
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
360 STRET_IMP(i1)
361 STRET_IMP(i2)
362 STRET_IMP(i3)
363 STRET_IMP(i4)
364 STRET_IMP(i5)
365 STRET_IMP(i6)
366 STRET_IMP(i7)
367 STRET_IMP(i8)
368 STRET_IMP(i9)
369
370 STRET_IMP(d1)
371 STRET_IMP(d2)
372 STRET_IMP(d3)
373 STRET_IMP(d4)
374 STRET_IMP(d5)
375 STRET_IMP(d6)
376 STRET_IMP(d7)
377 STRET_IMP(d8)
378 STRET_IMP(d9)
379
380
381 +(id)idret:
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
383 {
384 fail("+idret called instead of -idret");
385 CHECK_ARGS(idret);
386 }
387
388 +(long long)llret:
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
390 {
391 fail("+llret called instead of -llret");
392 CHECK_ARGS(llret);
393 }
394
395 +(struct stret)stret:
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
397 {
398 fail("+stret called instead of -stret");
399 CHECK_ARGS(stret);
400 }
401
402 +(double)fpret:
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
404 {
405 fail("+fpret called instead of -fpret");
406 CHECK_ARGS(fpret);
407 }
408
409 +(long double)lfpret:
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
411 {
412 fail("+lfpret called instead of -lfpret");
413 CHECK_ARGS(lfpret);
414 }
415
416 +(id)idret_noarg
417 {
418 fail("+idret_noarg called instead of -idret_noarg");
419 CHECK_ARGS_NOARG(idret);
420 }
421
422 +(long long)llret_noarg
423 {
424 fail("+llret_noarg called instead of -llret_noarg");
425 CHECK_ARGS_NOARG(llret);
426 }
427
428 +(struct stret)stret_noarg
429 {
430 fail("+stret_noarg called instead of -stret_noarg");
431 CHECK_ARGS_NOARG(stret);
432 }
433
434 +(double)fpret_noarg
435 {
436 fail("+fpret_noarg called instead of -fpret_noarg");
437 CHECK_ARGS_NOARG(fpret);
438 }
439
440 +(long double)lfpret_noarg
441 {
442 fail("+lfpret_noarg called instead of -lfpret_noarg");
443 CHECK_ARGS_NOARG(lfpret);
444 }
445
446 @end
447
448
449 @implementation Sub
450
451 -(id)idret:
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
453 {
454 id result;
455 CHECK_ARGS(idret);
456 state = 100;
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);
460 state = 101;
461 return result;
462 }
463
464 -(long long)llret:
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
466 {
467 long long result;
468 CHECK_ARGS(llret);
469 state = 100;
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);
473 state = 102;
474 return result;
475 }
476
477 -(struct stret)stret:
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
479 {
480 struct stret result;
481 CHECK_ARGS(stret);
482 state = 100;
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));
486 state = 103;
487 return result;
488 }
489
490 -(double)fpret:
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
492 {
493 double result;
494 CHECK_ARGS(fpret);
495 state = 100;
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);
499 state = 104;
500 return result;
501 }
502
503 -(long double)lfpret:
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
505 {
506 long double result;
507 CHECK_ARGS(lfpret);
508 state = 100;
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);
512 state = 105;
513 return result;
514 }
515
516
517 -(id)idret_noarg
518 {
519 id result;
520 CHECK_ARGS_NOARG(idret);
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
529 -(long long)llret_noarg
530 {
531 long long result;
532 CHECK_ARGS_NOARG(llret);
533 state = 100;
534 result = [super llret_noarg];
535 testassert(state == 12);
536 testassert(result == LL_RESULT);
537 state = 112;
538 return result;
539 }
540
541 -(struct stret)stret_noarg
542 {
543 struct stret result;
544 CHECK_ARGS_NOARG(stret);
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 }
552
553 -(double)fpret_noarg
554 {
555 double result;
556 CHECK_ARGS_NOARG(fpret);
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
565 -(long double)lfpret_noarg
566 {
567 long double result;
568 CHECK_ARGS_NOARG(lfpret);
569 state = 100;
570 result = [super lfpret_noarg];
571 testassert(state == 15);
572 testassert(result == LFP_RESULT);
573 state = 115;
574 return result;
575 }
576
577 @end
578
579
580 #if OBJC_HAVE_TAGGED_POINTERS
581
582 @interface TaggedSub : Sub @end
583
584 @implementation TaggedSub : Sub
585
586 +(void)initialize
587 {
588 _objc_registerTaggedPointerClass(OBJC_TAG_7, self);
589 }
590
591 @end
592
593 #endif
594
595
596 // DWARF checking machinery
597
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
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
628 bool caught = false;
629 uintptr_t clobbered;
630
631 __BEGIN_DECLS
632 extern void callit(void *obj, void *sel, void *fn);
633 extern 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
640 typedef uint8_t insn_t;
641 #define BREAK_INSN ((insn_t)0xcc) // int3
642
643 uintptr_t r12 = 0;
644 uintptr_t r13 = 0;
645 uintptr_t r14 = 0;
646 uintptr_t r15 = 0;
647 uintptr_t rbx = 0;
648 uintptr_t rbp = 0;
649 uintptr_t rsp = 0;
650 uintptr_t rip = 0;
651
652 void handle_exception(x86_thread_state64_t *state)
653 {
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;
709 }
710
711
712 void sigtrap(int sig, siginfo_t *info, void *cc)
713 {
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
724 }
725
726 __asm__(
727 "\n .text"
728 "\n .globl _callit"
729 "\n _callit:"
730 // save sp and return address to variables
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:"
749 // save sp and return address to variables
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
764
765 // x86_64
766
767 #elif __i386__
768
769 #define OTOOL "/usr/bin/xcrun otool -arch i386 "
770
771 typedef uint8_t insn_t;
772 #define BREAK_INSN ((insn_t)0xcc) // int3
773
774 uintptr_t eip = 0;
775 uintptr_t esp = 0;
776 uintptr_t ebx = 0;
777 uintptr_t ebp = 0;
778 uintptr_t edi = 0;
779 uintptr_t esi = 0;
780 uintptr_t espfix = 0;
781
782 void 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
832 void 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
895 typedef uint32_t insn_t;
896 #define BREAK_INSN ((insn_t)0xd4200020) // brk #1
897
898 uintptr_t x19 = 0;
899 uintptr_t x20 = 0;
900 uintptr_t x21 = 0;
901 uintptr_t x22 = 0;
902 uintptr_t x23 = 0;
903 uintptr_t x24 = 0;
904 uintptr_t x25 = 0;
905 uintptr_t x26 = 0;
906 uintptr_t x27 = 0;
907 uintptr_t x28 = 0;
908 uintptr_t fp = 0;
909 uintptr_t sp = 0;
910 uintptr_t pc = 0;
911
912 void 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
1002 void 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
1062 insn_t set(uintptr_t dst, insn_t newvalue)
1063 {
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
1072 insn_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
1078 void unclobber(void *fn, uintptr_t offset, insn_t oldvalue)
1079 {
1080 set((uintptr_t)fn + offset, oldvalue);
1081 }
1082
1083
1084 uintptr_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;
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");
1098 unsetenv("DYLD_SHARED_REGION");
1099 unsetenv("DYLD_SHARED_CACHE_DIR");
1100 unsetenv("DYLD_SHARED_CACHE_DONT_VALIDATE");
1101 char *cmd;
1102 asprintf(&cmd, OTOOL "-tv -p _%s %s",
1103 symname, dl.dli_fname);
1104 testprintf("%s\n", cmd);
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 }
1115
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);
1130
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
1150 testassert(p > result);
1151 testassert(p < end);
1152 *p = ~0UL;
1153 #if __x86_64__
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
1156 p[-1] = ~0UL;
1157 #endif
1158 if (outBase) *outBase = base;
1159 return result;
1160 }
1161
1162 void CALLIT(void *o, void *sel_arg, SEL s, void *f, bool stret) __attribute__((noinline));
1163 void CALLIT(void *o, void *sel_arg, SEL s, void *f, bool stret)
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 }
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
1180 void test_dw_forward(void)
1181 {
1182 return;
1183 }
1184
1185 struct stret test_dw_forward_stret(void)
1186 {
1187 return zero;
1188 }
1189
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)
1196 // uncaughtAllowed is the number of acceptable unreachable instructions
1197 // (for example, the ones that handle the corrupt-cache-error case)
1198 void test_dw(const char *name, id sub, id tagged, bool stret,
1199 int uncaughtAllowed)
1200 {
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 }
1250
1251 void *fn = dlsym(RTLD_DEFAULT, name);
1252 testassert(fn);
1253
1254 // argument substitutions
1255
1256 void *sub_arg = (void*)objc_unretainedPointer(sub);
1257 void *tagged_arg = (void*)objc_unretainedPointer(tagged);
1258 void *sel_arg = (void*)sel;
1259
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
1264 Class cache_cls = object_getClass(sub);
1265
1266 if (strstr(name, "Super")) {
1267 // super version - replace receiver with objc_super
1268 // clear caches of superclass
1269 cache_cls = class_getSuperclass(cache_cls);
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
1280 uintptr_t *insnOffsets = getOffsets(fn, name, nil);
1281 uintptr_t offset;
1282 int uncaughtCount = 0;
1283 for (int oo = 0; insnOffsets[oo] != ~0UL; oo++) {
1284 offset = insnOffsets[oo];
1285 testprintf("OFFSET %lu\n", offset);
1286
1287 insn_t saved_insn = clobber(fn, offset);
1288 caught = false;
1289
1290 // nil
1291 if ((void*)objc_unretainedPointer(sub) == sub_arg) {
1292 SELF = nil;
1293 testprintf(" nil\n");
1294 CALLIT(nil, sel_arg, sel, fn, stret);
1295 CALLIT(nil, sel_arg, sel, fn, stret);
1296 }
1297
1298 // uncached
1299 SELF = sub;
1300 testprintf(" uncached\n");
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);
1305
1306 // cached
1307 SELF = sub;
1308 testprintf(" cached\n");
1309 CALLIT(sub_arg, sel_arg, sel, fn, stret);
1310 CALLIT(sub_arg, sel_arg, sel, fn, stret);
1311
1312 // uncached,tagged
1313 SELF = tagged;
1314 testprintf(" uncached,tagged\n");
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);
1319
1320 // cached,tagged
1321 SELF = tagged;
1322 testprintf(" cached,tagged\n");
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 }
1352
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 }
1364
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);
1376 }
1377
1378 free(insnOffsets);
1379 }
1380
1381
1382 // TEST_DWARF
1383 #endif
1384
1385
1386 void test_basic(id receiver)
1387 {
1388 id idval;
1389 long long llval;
1390 struct stret stretval;
1391 double fpval;
1392 long double lfpval;
1393
1394 // message uncached
1395 // message uncached long long
1396 // message uncached stret
1397 // message uncached fpret
1398 // message uncached fpret long double
1399 // message uncached noarg (as above)
1400 // message cached
1401 // message cached long long
1402 // message cached stret
1403 // message cached fpret
1404 // message cached fpret long double
1405 // message cached noarg (as above)
1406 // fixme verify that uncached lookup didn't happen the 2nd time?
1407 SELF = receiver;
1408 for (int i = 0; i < 5; i++) {
1409 testprintf("idret\n");
1410 state = 0;
1411 idval = nil;
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];
1413 testassert(state == 101);
1414 testassert(idval == ID_RESULT);
1415
1416 testprintf("llret\n");
1417 llval = 0;
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];
1419 testassert(state == 102);
1420 testassert(llval == LL_RESULT);
1421
1422 testprintf("stret\n");
1423 stretval = zero;
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];
1425 testassert(state == 103);
1426 testassert(stret_equal(stretval, STRET_RESULT));
1427
1428 testprintf("fpret\n");
1429 fpval = 0;
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];
1431 testassert(state == 104);
1432 testassert(fpval == FP_RESULT);
1433
1434 testprintf("lfpret\n");
1435 lfpval = 0;
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];
1437 testassert(state == 105);
1438 testassert(lfpval == LFP_RESULT);
1439
1440 #if __OBJC2__
1441 // explicitly call noarg messenger, even if compiler doesn't emit it
1442 state = 0;
1443 testprintf("idret noarg\n");
1444 idval = nil;
1445 idval = ((typeof(idmsg0))objc_msgSend_noarg)(receiver, @selector(idret_noarg));
1446 testassert(state == 111);
1447 testassert(idval == ID_RESULT);
1448
1449 llval = 0;
1450 testprintf("llret noarg\n");
1451 llval = ((typeof(llmsg0))objc_msgSend_noarg)(receiver, @selector(llret_noarg));
1452 testassert(state == 112);
1453 testassert(llval == LL_RESULT);
1454 /*
1455 no objc_msgSend_stret_noarg
1456 stretval = zero;
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];
1459 testassert(state == 113);
1460 testassert(stret_equal(stretval, STRET_RESULT));
1461 */
1462 # if !__i386__
1463 testprintf("fpret noarg\n");
1464 fpval = 0;
1465 fpval = ((typeof(fpmsg0))objc_msgSend_noarg)(receiver, @selector(fpret_noarg));
1466 testassert(state == 114);
1467 testassert(fpval == FP_RESULT);
1468 # endif
1469 # if !__i386__ && !__x86_64__
1470 testprintf("lfpret noarg\n");
1471 lfpval = 0;
1472 lfpval = ((typeof(lfpmsg0))objc_msgSend_noarg)(receiver, @selector(lfpret_noarg));
1473 testassert(state == 115);
1474 testassert(lfpval == LFP_RESULT);
1475 # endif
1476 #endif
1477 }
1478
1479 testprintf("basic done\n");
1480 }
1481
1482 int 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
1493 #if __x86_64__
1494 struct stret *stretptr;
1495 #endif
1496
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];
1523 #if OBJC_HAVE_TAGGED_POINTERS
1524 [TaggedSub class];
1525 #endif
1526
1527 ID_RESULT = [Super new];
1528
1529 Sub *sub = [Sub new];
1530 Super *sup = [Super new];
1531 #if OBJC_HAVE_TAGGED_POINTERS
1532 TaggedSub *tagged = objc_unretainedObject(_objc_makeTaggedPointer(OBJC_TAG_7, 999));
1533 #endif
1534
1535 // Basic cached and uncached dispatch.
1536 // Do this first before anything below caches stuff.
1537 testprintf("basic\n");
1538 test_basic(sub);
1539 #if OBJC_HAVE_TAGGED_POINTERS
1540 testprintf("basic tagged\n");
1541 test_basic(tagged);
1542 #endif
1543
1544 idmethod = class_getInstanceMethod([Super class], @selector(idret::::::::::::::::::::::::::::));
1545 testassert(idmethod);
1546 llmethod = class_getInstanceMethod([Super class], @selector(llret::::::::::::::::::::::::::::));
1547 testassert(llmethod);
1548 stretmethod = class_getInstanceMethod([Super class], @selector(stret::::::::::::::::::::::::::::));
1549 testassert(stretmethod);
1550 fpmethod = class_getInstanceMethod([Super class], @selector(fpret::::::::::::::::::::::::::::));
1551 testassert(fpmethod);
1552 lfpmethod = class_getInstanceMethod([Super class], @selector(lfpret::::::::::::::::::::::::::::));
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
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
1565 // fill cache first
1566 testprintf("time checks\n");
1567
1568 SELF = sub;
1569 [sub voidret_nop];
1570 [sub voidret_nop2];
1571 [sub llret_nop];
1572 [sub stret_nop];
1573 [sub fpret_nop];
1574 [sub lfpret_nop];
1575 [sub voidret_nop];
1576 [sub voidret_nop2];
1577 [sub llret_nop];
1578 [sub stret_nop];
1579 [sub fpret_nop];
1580 [sub lfpret_nop];
1581 [sub voidret_nop];
1582 [sub voidret_nop2];
1583 [sub llret_nop];
1584 [sub stret_nop];
1585 [sub fpret_nop];
1586 [sub lfpret_nop];
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
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
1597 #define COUNT 1000000
1598
1599 startTime = mach_absolute_time();
1600 ALIGN_();
1601 for (i = 0; i < COUNT; i++) {
1602 [sub voidret_nop];
1603 }
1604 totalTime = mach_absolute_time() - startTime;
1605 testprintf("time: voidret %llu\n", totalTime);
1606 targetTime = totalTime;
1607
1608 startTime = mach_absolute_time();
1609 ALIGN_();
1610 for (i = 0; i < COUNT; i++) {
1611 [sub voidret_nop2];
1612 }
1613 totalTime = mach_absolute_time() - startTime;
1614 testprintf("time: voidret2 %llu\n", totalTime);
1615 if (totalTime < targetTime) targetTime = totalTime;
1616
1617 startTime = mach_absolute_time();
1618 ALIGN_();
1619 for (i = 0; i < COUNT; i++) {
1620 [sub llret_nop];
1621 }
1622 totalTime = mach_absolute_time() - startTime;
1623 timecheck("llret ", totalTime, targetTime * 0.7, targetTime * 2.0);
1624
1625 startTime = mach_absolute_time();
1626 ALIGN_();
1627 for (i = 0; i < COUNT; i++) {
1628 [sub stret_nop];
1629 }
1630 totalTime = mach_absolute_time() - startTime;
1631 timecheck("stret ", totalTime, targetTime * 0.7, targetTime * 5.0);
1632
1633 startTime = mach_absolute_time();
1634 ALIGN_();
1635 for (i = 0; i < COUNT; i++) {
1636 [sub fpret_nop];
1637 }
1638 totalTime = mach_absolute_time() - startTime;
1639 timecheck("fpret ", totalTime, targetTime * 0.7, targetTime * 4.0);
1640
1641 startTime = mach_absolute_time();
1642 ALIGN_();
1643 for (i = 0; i < COUNT; i++) {
1644 [sub lfpret_nop];
1645 }
1646 totalTime = mach_absolute_time() - startTime;
1647 timecheck("lfpret", totalTime, targetTime * 0.7, targetTime * 4.0);
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
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
1662 testprintf("method_invoke\n");
1663
1664 SELF = sup;
1665
1666 state = 0;
1667 idval = nil;
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);
1669 testassert(state == 1);
1670 testassert(idval == ID_RESULT);
1671
1672 llval = 0;
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);
1674 testassert(state == 2);
1675 testassert(llval == LL_RESULT);
1676
1677 stretval = zero;
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);
1679 testassert(state == 3);
1680 testassert(stret_equal(stretval, STRET_RESULT));
1681
1682 fpval = 0;
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);
1684 testassert(state == 4);
1685 testassert(fpval == FP_RESULT);
1686
1687 lfpval = 0;
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);
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
1698 // Use NIL_RECEIVER to avoid compiler optimizations.
1699 testprintf("message to nil\n");
1700
1701 state = 0;
1702 idval = ID_RESULT;
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];
1704 testassert(state == 0);
1705 testassert(idval == nil);
1706
1707 state = 0;
1708 llval = LL_RESULT;
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];
1710 testassert(state == 0);
1711 testassert(llval == 0LL);
1712
1713 state = 0;
1714 stretval = zero;
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];
1716 testassert(state == 0);
1717 #if __clang__
1718 testassert(0 == memcmp(&stretval, &zero, sizeof(stretval)));
1719 #else
1720 // no stret result guarantee
1721 #endif
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
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
1743 state = 0;
1744 fpval = FP_RESULT;
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];
1746 testassert(state == 0);
1747 testassert(fpval == 0.0);
1748
1749 state = 0;
1750 lfpval = LFP_RESULT;
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];
1752 testassert(state == 0);
1753 testassert(lfpval == 0.0);
1754
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
1793 #if __OBJC2__
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);
1801
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);
1807
1808 // no stret_noarg messenger
1809
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
1825
1826
1827 #if __OBJC2__
1828 // rdar://8271364 objc_msgSendSuper2 must not change objc_super
1829 testprintf("super struct\n");
1830 struct objc_super sup_st = {
1831 sub,
1832 object_getClass(sub),
1833 };
1834
1835 SELF = sub;
1836
1837 state = 100;
1838 idval = nil;
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);
1840 testassert(state == 1);
1841 testassert(idval == ID_RESULT);
1842 testassert(sup_st.receiver == sub);
1843 testassert(sup_st.super_class == object_getClass(sub));
1844
1845 state = 100;
1846 stretval = zero;
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);
1848 testassert(state == 3);
1849 testassert(stret_equal(stretval, STRET_RESULT));
1850 testassert(sup_st.receiver == sub);
1851 testassert(sup_st.super_class == object_getClass(sub));
1852 #endif
1853
1854 #if __OBJC2__ && !__arm64__
1855 // Debug messengers.
1856 testprintf("debug messengers\n");
1857
1858 state = 0;
1859 idmsg = (typeof(idmsg))objc_msgSend_debug;
1860 idval = nil;
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);
1862 testassert(state == 101);
1863 testassert(idval == ID_RESULT);
1864
1865 state = 0;
1866 llmsg = (typeof(llmsg))objc_msgSend_debug;
1867 llval = 0;
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);
1869 testassert(state == 102);
1870 testassert(llval == LL_RESULT);
1871
1872 state = 0;
1873 stretmsg = (typeof(stretmsg))objc_msgSend_stret_debug;
1874 stretval = zero;
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);
1876 testassert(state == 103);
1877 testassert(stret_equal(stretval, STRET_RESULT));
1878
1879 state = 100;
1880 sup_st.receiver = sub;
1881 sup_st.super_class = object_getClass(sub);
1882 idmsgsuper = (typeof(idmsgsuper))objc_msgSendSuper2_debug;
1883 idval = nil;
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);
1885 testassert(state == 1);
1886 testassert(idval == ID_RESULT);
1887
1888 state = 100;
1889 sup_st.receiver = sub;
1890 sup_st.super_class = object_getClass(sub);
1891 stretmsgsuper = (typeof(stretmsgsuper))objc_msgSendSuper2_stret_debug;
1892 stretval = zero;
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);
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;
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);
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;
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);
1910 testassert(state == 105);
1911 testassert(lfpval == LFP_RESULT);
1912
1913 // fixme fp2ret
1914 #endif
1915
1916 // debug messengers
1917 #endif
1918
1919
1920 #if !TEST_DWARF
1921 testwarn("no unwind tables in this configuration");
1922 #else
1923 // DWARF unwind tables
1924 testprintf("unwind tables\n");
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
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
1961
1962 // DWARF unwind tables
1963 #endif
1964
1965 } POP_POOL;
1966 succeed(__FILE__);
1967 }
1968
1969 #endif