]> git.saurik.com Git - apple/objc4.git/blob - test/msgSend.m
objc4-532.2.tar.gz
[apple/objc4.git] / test / msgSend.m
1 // TEST_CONFIG
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 defined(__arm__)
22 // rdar://8331406
23 # define ALIGN_()
24 #else
25 # define ALIGN_() asm(".align 4");
26 #endif
27
28 @interface Super : TestRoot @end
29
30 @interface Sub : Super @end
31
32 static int state = 0;
33
34 static id SELF;
35
36 // for typeof() shorthand only
37 id (*idmsg0)(id, SEL) __attribute__((unused));
38 long long (*llmsg0)(id, SEL) __attribute__((unused));
39 // struct stret (*stretmsg0)(id, SEL) __attribute__((unused));
40 double (*fpmsg0)(id, SEL) __attribute__((unused));
41 long double (*lfpmsg0)(id, SEL) __attribute__((unused));
42
43
44 #define CHECK_ARGS(sel) \
45 do { \
46 testassert(self == SELF); \
47 testassert(_cmd == sel_registerName(#sel "::::::::::::::::::::::::::::"));\
48 testassert(i1 == 1); \
49 testassert(i2 == 2); \
50 testassert(i3 == 3); \
51 testassert(i4 == 4); \
52 testassert(i5 == 5); \
53 testassert(i6 == 6); \
54 testassert(i7 == 7); \
55 testassert(i8 == 8); \
56 testassert(i9 == 9); \
57 testassert(i10 == 10); \
58 testassert(i11 == 11); \
59 testassert(i12 == 12); \
60 testassert(i13 == 13); \
61 testassert(f1 == 1.0); \
62 testassert(f2 == 2.0); \
63 testassert(f3 == 3.0); \
64 testassert(f4 == 4.0); \
65 testassert(f5 == 5.0); \
66 testassert(f6 == 6.0); \
67 testassert(f7 == 7.0); \
68 testassert(f8 == 8.0); \
69 testassert(f9 == 9.0); \
70 testassert(f10 == 10.0); \
71 testassert(f11 == 11.0); \
72 testassert(f12 == 12.0); \
73 testassert(f13 == 13.0); \
74 testassert(f14 == 14.0); \
75 testassert(f15 == 15.0); \
76 } while (0)
77
78 #define CHECK_ARGS_NOARG(sel) \
79 do { \
80 testassert(self == SELF); \
81 testassert(_cmd == sel_registerName(#sel "_noarg"));\
82 } while (0)
83
84 id ID_RESULT;
85 long long LL_RESULT = __LONG_LONG_MAX__ - 2LL*__INT_MAX__;
86 double FP_RESULT = __DBL_MIN__ + __DBL_EPSILON__;
87 long double LFP_RESULT = __LDBL_MIN__ + __LDBL_EPSILON__;
88 // STRET_RESULT in test.h
89
90 static struct stret zero;
91
92
93 @implementation Super
94 -(struct stret)stret { return STRET_RESULT; }
95
96 -(id)idret:
97 (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
98 {
99 CHECK_ARGS(idret);
100 state = 1;
101 return ID_RESULT;
102 }
103
104 -(long long)llret:
105 (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
106 {
107 CHECK_ARGS(llret);
108 state = 2;
109 return LL_RESULT;
110 }
111
112 -(struct stret)stret:
113 (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
114 {
115 CHECK_ARGS(stret);
116 state = 3;
117 return STRET_RESULT;
118 }
119
120 -(double)fpret:
121 (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
122 {
123 CHECK_ARGS(fpret);
124 state = 4;
125 return FP_RESULT;
126 }
127
128 -(long double)lfpret:
129 (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
130 {
131 CHECK_ARGS(lfpret);
132 state = 5;
133 return LFP_RESULT;
134 }
135
136
137 -(id)idret_noarg
138 {
139 CHECK_ARGS_NOARG(idret);
140 state = 11;
141 return ID_RESULT;
142 }
143
144 -(long long)llret_noarg
145 {
146 CHECK_ARGS_NOARG(llret);
147 state = 12;
148 return LL_RESULT;
149 }
150
151 -(struct stret)stret_noarg
152 {
153 CHECK_ARGS_NOARG(stret);
154 state = 13;
155 return STRET_RESULT;
156 }
157
158 -(double)fpret_noarg
159 {
160 CHECK_ARGS_NOARG(fpret);
161 state = 14;
162 return FP_RESULT;
163 }
164
165 -(long double)lfpret_noarg
166 {
167 CHECK_ARGS_NOARG(lfpret);
168 state = 15;
169 return LFP_RESULT;
170 }
171
172
173 -(void)voidret_nop
174 {
175 return;
176 }
177
178 -(id)idret_nop
179 {
180 return ID_RESULT;
181 }
182
183 -(long long)llret_nop
184 {
185 return LL_RESULT;
186 }
187
188 -(struct stret)stret_nop
189 {
190 return STRET_RESULT;
191 }
192
193 -(double)fpret_nop
194 {
195 return FP_RESULT;
196 }
197
198 -(long double)lfpret_nop
199 {
200 return LFP_RESULT;
201 }
202
203
204
205 +(id)idret:
206 (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
207 {
208 fail("+idret called instead of -idret");
209 CHECK_ARGS(idret);
210 }
211
212 +(long long)llret:
213 (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
214 {
215 fail("+llret called instead of -llret");
216 CHECK_ARGS(llret);
217 }
218
219 +(struct stret)stret:
220 (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
221 {
222 fail("+stret called instead of -stret");
223 CHECK_ARGS(stret);
224 }
225
226 +(double)fpret:
227 (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
228 {
229 fail("+fpret called instead of -fpret");
230 CHECK_ARGS(fpret);
231 }
232
233 +(long double)lfpret:
234 (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
235 {
236 fail("+lfpret called instead of -lfpret");
237 CHECK_ARGS(lfpret);
238 }
239
240 +(id)idret_noarg
241 {
242 fail("+idret_noarg called instead of -idret_noarg");
243 CHECK_ARGS_NOARG(idret);
244 }
245
246 +(long long)llret_noarg
247 {
248 fail("+llret_noarg called instead of -llret_noarg");
249 CHECK_ARGS_NOARG(llret);
250 }
251
252 +(struct stret)stret_noarg
253 {
254 fail("+stret_noarg called instead of -stret_noarg");
255 CHECK_ARGS_NOARG(stret);
256 }
257
258 +(double)fpret_noarg
259 {
260 fail("+fpret_noarg called instead of -fpret_noarg");
261 CHECK_ARGS_NOARG(fpret);
262 }
263
264 +(long double)lfpret_noarg
265 {
266 fail("+lfpret_noarg called instead of -lfpret_noarg");
267 CHECK_ARGS_NOARG(lfpret);
268 }
269
270 @end
271
272
273 @implementation Sub
274
275 -(id)idret:
276 (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
277 {
278 id result;
279 CHECK_ARGS(idret);
280 state = 100;
281 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];
282 testassert(state == 1);
283 testassert(result == ID_RESULT);
284 state = 101;
285 return result;
286 }
287
288 -(long long)llret:
289 (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
290 {
291 long long result;
292 CHECK_ARGS(llret);
293 state = 100;
294 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];
295 testassert(state == 2);
296 testassert(result == LL_RESULT);
297 state = 102;
298 return result;
299 }
300
301 -(struct stret)stret:
302 (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
303 {
304 struct stret result;
305 CHECK_ARGS(stret);
306 state = 100;
307 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];
308 testassert(state == 3);
309 testassert(stret_equal(result, STRET_RESULT));
310 state = 103;
311 return result;
312 }
313
314 -(double)fpret:
315 (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
316 {
317 double result;
318 CHECK_ARGS(fpret);
319 state = 100;
320 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];
321 testassert(state == 4);
322 testassert(result == FP_RESULT);
323 state = 104;
324 return result;
325 }
326
327 -(long double)lfpret:
328 (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
329 {
330 long double result;
331 CHECK_ARGS(lfpret);
332 state = 100;
333 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];
334 testassert(state == 5);
335 testassert(result == LFP_RESULT);
336 state = 105;
337 return result;
338 }
339
340
341 -(id)idret_noarg
342 {
343 id result;
344 CHECK_ARGS_NOARG(idret);
345 state = 100;
346 result = [super idret_noarg];
347 testassert(state == 11);
348 testassert(result == ID_RESULT);
349 state = 111;
350 return result;
351 }
352
353 -(long long)llret_noarg
354 {
355 long long result;
356 CHECK_ARGS_NOARG(llret);
357 state = 100;
358 result = [super llret_noarg];
359 testassert(state == 12);
360 testassert(result == LL_RESULT);
361 state = 112;
362 return result;
363 }
364
365 -(struct stret)stret_noarg
366 {
367 struct stret result;
368 CHECK_ARGS_NOARG(stret);
369 state = 100;
370 result = [super stret_noarg];
371 testassert(state == 13);
372 testassert(stret_equal(result, STRET_RESULT));
373 state = 113;
374 return result;
375 }
376
377 -(double)fpret_noarg
378 {
379 double result;
380 CHECK_ARGS_NOARG(fpret);
381 state = 100;
382 result = [super fpret_noarg];
383 testassert(state == 14);
384 testassert(result == FP_RESULT);
385 state = 114;
386 return result;
387 }
388
389 -(long double)lfpret_noarg
390 {
391 long double result;
392 CHECK_ARGS_NOARG(lfpret);
393 state = 100;
394 result = [super lfpret_noarg];
395 testassert(state == 15);
396 testassert(result == LFP_RESULT);
397 state = 115;
398 return result;
399 }
400
401 @end
402
403
404 #if __x86_64__
405
406 @interface TaggedSub : Sub @end
407
408 @implementation TaggedSub : Sub
409
410 #define TAG_VALUE(tagSlot, value) (objc_unretainedObject((void*)(1UL | (((uintptr_t)(tagSlot)) << 1) | (((uintptr_t)(value)) << 4))))
411
412 +(void)initialize
413 {
414 _objc_insert_tagged_isa(2, self);
415 }
416
417 @end
418
419 // DWARF checking machinery
420
421 #include <dlfcn.h>
422 #include <signal.h>
423 #include <sys/mman.h>
424 #include <libunwind.h>
425
426 #define UNW_STEP_SUCCESS 1
427 #define UNW_STEP_END 0
428
429 bool caught = false;
430 uintptr_t clobbered;
431
432 uintptr_t r12 = 0;
433 uintptr_t r13 = 0;
434 uintptr_t r14 = 0;
435 uintptr_t r15 = 0;
436 uintptr_t rbx = 0;
437 uintptr_t rbp = 0;
438 uintptr_t rsp = 0;
439 uintptr_t rip = 0;
440
441 void handle_exception(x86_thread_state64_t *state)
442 {
443 unw_cursor_t curs;
444 unw_word_t reg;
445 int err;
446 int step;
447
448 err = unw_init_local(&curs, (unw_context_t *)state);
449 testassert(!err);
450
451 step = unw_step(&curs);
452 testassert(step == UNW_STEP_SUCCESS);
453
454 err = unw_get_reg(&curs, UNW_X86_64_R12, &reg);
455 testassert(!err);
456 testassert(reg == r12);
457
458 err = unw_get_reg(&curs, UNW_X86_64_R13, &reg);
459 testassert(!err);
460 testassert(reg == r13);
461
462 err = unw_get_reg(&curs, UNW_X86_64_R14, &reg);
463 testassert(!err);
464 testassert(reg == r14);
465
466 err = unw_get_reg(&curs, UNW_X86_64_R15, &reg);
467 testassert(!err);
468 testassert(reg == r15);
469
470 err = unw_get_reg(&curs, UNW_X86_64_RBX, &reg);
471 testassert(!err);
472 testassert(reg == rbx);
473
474 err = unw_get_reg(&curs, UNW_X86_64_RBP, &reg);
475 testassert(!err);
476 testassert(reg == rbp);
477
478 err = unw_get_reg(&curs, UNW_X86_64_RSP, &reg);
479 testassert(!err);
480 testassert(reg == rsp);
481
482 err = unw_get_reg(&curs, UNW_REG_IP, &reg);
483 testassert(!err);
484 testassert(reg == rip);
485
486
487 // set thread state to unwound state
488 state->__r12 = r12;
489 state->__r13 = r13;
490 state->__r14 = r14;
491 state->__r15 = r15;
492 state->__rbx = rbx;
493 state->__rbp = rbp;
494 state->__rsp = rsp;
495 state->__rip = rip;
496
497 caught = true;
498 }
499
500
501 void sigtrap(int sig, siginfo_t *info, void *cc)
502 {
503 ucontext_t *uc = (ucontext_t *)cc;
504 mcontext_t mc = (mcontext_t)uc->uc_mcontext;
505
506 testprintf(" handled\n");
507
508 testassert(sig == SIGTRAP);
509 testassert((uintptr_t)info->si_addr-1 == clobbered);
510
511 handle_exception(&mc->__ss);
512 // handle_exception changed register state for continuation
513 }
514
515
516 uint8_t set(uintptr_t dst, uint8_t newvalue)
517 {
518 uintptr_t start = dst & ~(4096-1);
519 mprotect((void*)start, 4096, PROT_READ|PROT_WRITE);
520 // int3
521 uint8_t oldvalue = *(uint8_t *)dst;
522 *(uint8_t *)dst = newvalue;
523 mprotect((void*)start, 4096, PROT_READ|PROT_EXEC);
524 return oldvalue;
525 }
526
527 uint8_t clobber(void *fn, uintptr_t offset)
528 {
529 clobbered = (uintptr_t)fn + offset;
530 return set((uintptr_t)fn + offset, 0xcc /*int3*/);
531 }
532
533 void unclobber(void *fn, uintptr_t offset, uint8_t oldvalue)
534 {
535 set((uintptr_t)fn + offset, oldvalue);
536 }
537
538 __BEGIN_DECLS
539 extern void callit(void *obj, void *sel, void *fn);
540 extern struct stret callit_stret(void *obj, void *sel, void *fn);
541 __END_DECLS
542
543 __asm__(
544 "\n .text"
545 "\n .globl _callit"
546 "\n _callit:"
547 // save rsp and rip registers to variables
548 "\n movq (%rsp), %r10"
549 "\n movq %r10, _rip(%rip)"
550 "\n movq %rsp, _rsp(%rip)"
551 "\n addq $8, _rsp(%rip)" // rewind to pre-call value
552 // save other non-volatile registers to variables
553 "\n movq %rbx, _rbx(%rip)"
554 "\n movq %rbp, _rbp(%rip)"
555 "\n movq %r12, _r12(%rip)"
556 "\n movq %r13, _r13(%rip)"
557 "\n movq %r14, _r14(%rip)"
558 "\n movq %r15, _r15(%rip)"
559 "\n jmpq *%rdx"
560 );
561
562 __asm__(
563 "\n .text"
564 "\n .globl _callit_stret"
565 "\n _callit_stret:"
566 // save rsp and rip registers to variables
567 "\n movq (%rsp), %r10"
568 "\n movq %r10, _rip(%rip)"
569 "\n movq %rsp, _rsp(%rip)"
570 "\n addq $8, _rsp(%rip)" // rewind to pre-call value
571 // save other non-volatile registers to variables
572 "\n movq %rbx, _rbx(%rip)"
573 "\n movq %rbp, _rbp(%rip)"
574 "\n movq %r12, _r12(%rip)"
575 "\n movq %r13, _r13(%rip)"
576 "\n movq %r14, _r14(%rip)"
577 "\n movq %r15, _r15(%rip)"
578 "\n jmpq *%rcx"
579 );
580
581 uintptr_t *getOffsets(void *symbol, const char *symname)
582 {
583 uintptr_t *result = (uintptr_t *)malloc(4096 * sizeof(uintptr_t));
584 uintptr_t *end = result + 4096;
585 uintptr_t *p = result;
586
587 // find library
588 Dl_info dl;
589 dladdr(symbol, &dl);
590
591 // call `otool` on library
592 unsetenv("DYLD_LIBRARY_PATH");
593 unsetenv("DYLD_ROOT_PATH");
594 unsetenv("DYLD_INSERT_LIBRARIES");
595 char *cmd;
596 asprintf(&cmd, "/usr/bin/xcrun otool -arch x86_64 -tv -p _%s %s",
597 symname, dl.dli_fname);
598 FILE *disa = popen(cmd, "r");
599 free(cmd);
600 testassert(disa);
601
602 // read past "_symname:" line
603 char *line;
604 size_t len;
605 while ((line = fgetln(disa, &len))) {
606 if (0 == strncmp(1+line, symname, MIN(len-1, strlen(symname)))) break;
607 }
608
609 // read instructions and save offsets
610 char op[128];
611 long base = 0;
612 long addr;
613 while (2 == fscanf(disa, "%lx%s%*[^\n]\n", &addr, op)) {
614 if (base == 0) base = addr;
615 if (0 != strncmp(op, "nop", 3)) {
616 testassert(p < end);
617 *p++ = addr - base;
618 } else {
619 // assume nops are unreached (e.g. alignment padding)
620 }
621 }
622 pclose(disa);
623
624 testassert(p > result);
625 testassert(p < end);
626 *p = ~0UL;
627 return result;
628 }
629
630 void CALLIT(void *o, void *sel_arg, SEL s, void *f) __attribute__((noinline));
631 void CALLIT(void *o, void *sel_arg, SEL s, void *f)
632 {
633 uintptr_t message_ref[2];
634 if (sel_arg != s) {
635 // fixup dispatch
636 // copy to a local buffer to keep sel_arg un-fixed-up
637 memcpy(message_ref, sel_arg, sizeof(message_ref));
638 sel_arg = message_ref;
639 }
640 if (s == @selector(idret_nop)) callit(o, sel_arg, f);
641 else if (s == @selector(fpret_nop)) callit(o, sel_arg, f);
642 else if (s == @selector(stret_nop)) callit_stret(o, sel_arg, f);
643 else fail("test_dw selector");
644 }
645
646 // sub = ordinary receiver object
647 // tagged = tagged receiver object
648 // SEL = selector to send
649 // sub_arg = arg to pass in receiver register (may be objc_super struct)
650 // tagged_arg = arg to pass in receiver register (may be objc_super struct)
651 // sel_arg = arg to pass in sel register (may be message_ref)
652 void test_dw(const char *name, id sub, id tagged, SEL sel)
653 {
654 testprintf("DWARF FOR %s\n", name);
655
656 void *fn = dlsym(RTLD_DEFAULT, name);
657 testassert(fn);
658
659 // argument substitutions
660
661 void *sub_arg = (void*)objc_unretainedPointer(sub);
662 void *tagged_arg = (void*)objc_unretainedPointer(tagged);
663 void *sel_arg = (void*)sel;
664
665 struct objc_super sup_st = { sub, object_getClass(sub) };
666 struct objc_super tagged_sup_st = { tagged, object_getClass(tagged) };
667 struct { void *imp; SEL sel; } message_ref = { fn, sel };
668
669 if (strstr(name, "Super")) {
670 // super version - replace receiver with objc_super
671 sub_arg = &sup_st;
672 tagged_arg = &tagged_sup_st;
673 }
674
675 if (strstr(name, "_fixup")) {
676 // fixup version - replace sel with message_ref
677 sel_arg = &message_ref;
678 }
679
680
681 uintptr_t *insnOffsets = getOffsets(fn, name);
682 uintptr_t *offsetp = insnOffsets;
683 uintptr_t offset;
684 while ((offset = *offsetp++) != ~0UL) {
685 testprintf("OFFSET %lu\n", offset);
686
687 uint8_t insn_byte = clobber(fn, offset);
688 caught = false;
689
690 // nil
691 if ((void*)objc_unretainedPointer(sub) == sub_arg) {
692 SELF = nil;
693 testprintf(" nil\n");
694 CALLIT(nil, sel_arg, sel, fn);
695 CALLIT(nil, sel_arg, sel, fn);
696 }
697
698 // uncached
699 SELF = sub;
700 testprintf(" uncached\n");
701 _objc_flush_caches(object_getClass(sub));
702 CALLIT(sub_arg, sel_arg, sel, fn);
703 _objc_flush_caches(object_getClass(sub));
704 CALLIT(sub_arg, sel_arg, sel, fn);
705
706 // cached
707 SELF = sub;
708 testprintf(" cached\n");
709 CALLIT(sub_arg, sel_arg, sel, fn);
710 CALLIT(sub_arg, sel_arg, sel, fn);
711
712 // uncached,tagged
713 SELF = tagged;
714 testprintf(" uncached,tagged\n");
715 _objc_flush_caches(object_getClass(tagged));
716 CALLIT(tagged_arg, sel_arg, sel, fn);
717 _objc_flush_caches(object_getClass(tagged));
718 CALLIT(tagged_arg, sel_arg, sel, fn);
719
720 // cached,tagged
721 SELF = tagged;
722 testprintf(" cached,tagged\n");
723 CALLIT(tagged_arg, sel_arg, sel, fn);
724 CALLIT(tagged_arg, sel_arg, sel, fn);
725
726 unclobber(fn, offset, insn_byte);
727
728 // require at least one path above to trip this offset
729 if (!caught) fprintf(stderr, "OFFSET %lu NOT CAUGHT\n", offset);
730 }
731 free(insnOffsets);
732 }
733
734 // x86_64
735 #endif
736
737
738 void test_basic(id receiver)
739 {
740 id idval;
741 long long llval;
742 struct stret stretval;
743 double fpval;
744 long double lfpval;
745
746 // message uncached
747 // message uncached long long
748 // message uncached stret
749 // message uncached fpret
750 // message uncached fpret long double
751 // message uncached noarg (as above)
752 // message cached
753 // message cached long long
754 // message cached stret
755 // message cached fpret
756 // message cached fpret long double
757 // message cached noarg (as above)
758 // fixme verify that uncached lookup didn't happen the 2nd time?
759 SELF = receiver;
760 for (int i = 0; i < 5; i++) {
761 state = 0;
762 idval = nil;
763 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];
764 testassert(state == 101);
765 testassert(idval == ID_RESULT);
766
767 llval = 0;
768 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];
769 testassert(state == 102);
770 testassert(llval == LL_RESULT);
771
772 stretval = zero;
773 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];
774 testassert(state == 103);
775 testassert(stret_equal(stretval, STRET_RESULT));
776
777 fpval = 0;
778 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];
779 testassert(state == 104);
780 testassert(fpval == FP_RESULT);
781
782 lfpval = 0;
783 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];
784 testassert(state == 105);
785 testassert(lfpval == LFP_RESULT);
786
787 #if __OBJC2__
788 // explicitly call noarg messenger, even if compiler doesn't emit it
789 state = 0;
790 idval = nil;
791 idval = ((typeof(idmsg0))objc_msgSend_noarg)(receiver, @selector(idret_noarg));
792 testassert(state == 111);
793 testassert(idval == ID_RESULT);
794
795 llval = 0;
796 llval = ((typeof(llmsg0))objc_msgSend_noarg)(receiver, @selector(llret_noarg));
797 testassert(state == 112);
798 testassert(llval == LL_RESULT);
799 /*
800 no objc_msgSend_stret_noarg
801 stretval = zero;
802 stretval = ((typeof(stretmsg0))objc_msgSend_stret_noarg)(receiver, @selector(stret_noarg));
803 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];
804 testassert(state == 113);
805 testassert(stret_equal(stretval, STRET_RESULT));
806 */
807 # if !__i386__
808 fpval = 0;
809 fpval = ((typeof(fpmsg0))objc_msgSend_noarg)(receiver, @selector(fpret_noarg));
810 testassert(state == 114);
811 testassert(fpval == FP_RESULT);
812 # endif
813 # if !__i386__ && !__x86_64__
814 lfpval = 0;
815 lfpval = ((typeof(lfpmsg0))objc_msgSend_noarg)(receiver, @selector(lfpret_noarg));
816 testassert(state == 115);
817 testassert(lfpval == LFP_RESULT);
818 # endif
819 #endif
820 }
821 }
822
823 int main()
824 {
825 PUSH_POOL {
826 int i;
827
828 id idval;
829 long long llval;
830 struct stret stretval;
831 double fpval;
832 long double lfpval;
833
834 uint64_t startTime;
835 uint64_t totalTime;
836 uint64_t targetTime;
837
838 Method idmethod;
839 Method llmethod;
840 Method stretmethod;
841 Method fpmethod;
842 Method lfpmethod;
843
844 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);
845 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);
846 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);
847 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);
848 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);
849
850 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));
851 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));
852 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));
853 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));
854 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));
855 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));
856 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));
857
858 // get +initialize out of the way
859 [Sub class];
860 #if __x86_64__
861 [TaggedSub class];
862 #endif
863
864 ID_RESULT = [Super new];
865
866 Sub *sub = [Sub new];
867 Super *sup = [Super new];
868 #if __x86_64__
869 TaggedSub *tagged = TAG_VALUE(2, 999);
870 #endif
871
872 // Basic cached and uncached dispatch.
873 // Do this first before anything below caches stuff.
874 test_basic(sub);
875 #if __x86_64__
876 test_basic(tagged);
877 #endif
878
879 idmethod = class_getInstanceMethod([Super class], @selector(idret::::::::::::::::::::::::::::));
880 testassert(idmethod);
881 llmethod = class_getInstanceMethod([Super class], @selector(llret::::::::::::::::::::::::::::));
882 testassert(llmethod);
883 stretmethod = class_getInstanceMethod([Super class], @selector(stret::::::::::::::::::::::::::::));
884 testassert(stretmethod);
885 fpmethod = class_getInstanceMethod([Super class], @selector(fpret::::::::::::::::::::::::::::));
886 testassert(fpmethod);
887 lfpmethod = class_getInstanceMethod([Super class], @selector(lfpret::::::::::::::::::::::::::::));
888 testassert(lfpmethod);
889
890 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;
891 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;
892 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;
893 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;
894 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;
895
896 // cached message performance
897 // catches failure to cache or (abi=2) failure to fixup (#5584187)
898 // fixme unless they all fail
899 // `.align 4` matches loop alignment to make -O0 work
900 // fill cache first
901 SELF = sub;
902 [sub voidret_nop];
903 [sub llret_nop];
904 [sub stret_nop];
905 [sub fpret_nop];
906 [sub lfpret_nop];
907 [sub voidret_nop];
908 [sub llret_nop];
909 [sub stret_nop];
910 [sub fpret_nop];
911 [sub lfpret_nop];
912 [sub voidret_nop];
913 [sub llret_nop];
914 [sub stret_nop];
915 [sub fpret_nop];
916 [sub lfpret_nop];
917
918 // Some of these times have high variance on some compilers.
919 // The errors we're trying to catch should be catastrophically slow,
920 // so the margins here are generous to avoid false failures.
921
922 #define COUNT 1000000
923 startTime = mach_absolute_time();
924 ALIGN_();
925 for (i = 0; i < COUNT; i++) {
926 [sub voidret_nop]; // id return is too slow for perf test with ARC
927 }
928 totalTime = mach_absolute_time() - startTime;
929 testprintf("time: idret %llu\n", totalTime);
930 targetTime = totalTime;
931
932 startTime = mach_absolute_time();
933 ALIGN_();
934 for (i = 0; i < COUNT; i++) {
935 [sub voidret_nop]; // id return is too slow for perf test with ARC
936 }
937 totalTime = mach_absolute_time() - startTime;
938 testprintf("time: idret %llu\n", totalTime);
939 targetTime = totalTime;
940
941 startTime = mach_absolute_time();
942 ALIGN_();
943 for (i = 0; i < COUNT; i++) {
944 [sub llret_nop];
945 }
946 totalTime = mach_absolute_time() - startTime;
947 timecheck("llret ", totalTime, targetTime * 0.7, targetTime * 2.0);
948
949 startTime = mach_absolute_time();
950 ALIGN_();
951 for (i = 0; i < COUNT; i++) {
952 [sub stret_nop];
953 }
954 totalTime = mach_absolute_time() - startTime;
955 timecheck("stret ", totalTime, targetTime * 0.7, targetTime * 5.0);
956
957 startTime = mach_absolute_time();
958 ALIGN_();
959 for (i = 0; i < COUNT; i++) {
960 [sub fpret_nop];
961 }
962 totalTime = mach_absolute_time() - startTime;
963 timecheck("fpret ", totalTime, targetTime * 0.7, targetTime * 4.0);
964
965 startTime = mach_absolute_time();
966 ALIGN_();
967 for (i = 0; i < COUNT; i++) {
968 [sub lfpret_nop];
969 }
970 totalTime = mach_absolute_time() - startTime;
971 timecheck("lfpret", totalTime, targetTime * 0.7, targetTime * 4.0);
972 #undef COUNT
973
974 // method_invoke
975 // method_invoke long long
976 // method_invoke_stret stret
977 // method_invoke_stret fpret
978 // method_invoke fpret long double
979 SELF = sup;
980
981 state = 0;
982 idval = nil;
983 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);
984 testassert(state == 1);
985 testassert(idval == ID_RESULT);
986
987 llval = 0;
988 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);
989 testassert(state == 2);
990 testassert(llval == LL_RESULT);
991
992 stretval = zero;
993 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);
994 testassert(state == 3);
995 testassert(stret_equal(stretval, STRET_RESULT));
996
997 fpval = 0;
998 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);
999 testassert(state == 4);
1000 testassert(fpval == FP_RESULT);
1001
1002 lfpval = 0;
1003 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);
1004 testassert(state == 5);
1005 testassert(lfpval == LFP_RESULT);
1006
1007
1008 // message to nil
1009 // message to nil long long
1010 // message to nil stret
1011 // message to nil fpret
1012 // message to nil fpret long double
1013 state = 0;
1014 idval = ID_RESULT;
1015 idval = [(id)nil 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];
1016 testassert(state == 0);
1017 testassert(idval == nil);
1018
1019 state = 0;
1020 llval = LL_RESULT;
1021 llval = [(id)nil 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];
1022 testassert(state == 0);
1023 testassert(llval == 0LL);
1024
1025 state = 0;
1026 stretval = zero;
1027 stretval = [(id)nil 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];
1028 testassert(state == 0);
1029 #if __clang__
1030 testassert(0 == memcmp(&stretval, &zero, sizeof(stretval)));
1031 #else
1032 // no stret result guarantee
1033 #endif
1034
1035 state = 0;
1036 fpval = FP_RESULT;
1037 fpval = [(id)nil 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];
1038 testassert(state == 0);
1039 testassert(fpval == 0.0);
1040
1041 state = 0;
1042 lfpval = LFP_RESULT;
1043 lfpval = [(id)nil 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];
1044 testassert(state == 0);
1045 testassert(lfpval == 0.0);
1046
1047 #if __OBJC2__
1048 // message to nil noarg
1049 // explicitly call noarg messenger, even if compiler doesn't emit it
1050 state = 0;
1051 idval = ID_RESULT;
1052 idval = ((typeof(idmsg0))objc_msgSend_noarg)(nil, @selector(idret_noarg));
1053 testassert(state == 0);
1054 testassert(idval == nil);
1055
1056 state = 0;
1057 llval = LL_RESULT;
1058 llval = ((typeof(llmsg0))objc_msgSend_noarg)(nil, @selector(llret_noarg));
1059 testassert(state == 0);
1060 testassert(llval == 0LL);
1061
1062 // no stret_noarg messenger
1063
1064 # if !__i386__
1065 state = 0;
1066 fpval = FP_RESULT;
1067 fpval = ((typeof(fpmsg0))objc_msgSend_noarg)(nil, @selector(fpret_noarg));
1068 testassert(state == 0);
1069 testassert(fpval == 0.0);
1070 # endif
1071 # if !__i386__ && !__x86_64__
1072 state = 0;
1073 lfpval = LFP_RESULT;
1074 lfpval = ((typeof(lfpmsg0))objc_msgSend_noarg)(nil, @selector(lfpret_noarg));
1075 testassert(state == 0);
1076 testassert(lfpval == 0.0);
1077 # endif
1078 #endif
1079
1080 // message forwarded
1081 // message forwarded long long
1082 // message forwarded stret
1083 // message forwarded fpret
1084 // message forwarded fpret long double
1085 // fixme
1086
1087 #if __OBJC2__
1088 // rdar://8271364 objc_msgSendSuper2 must not change objc_super
1089 struct objc_super sup_st = {
1090 sub,
1091 object_getClass(sub),
1092 };
1093
1094 SELF = sub;
1095
1096 state = 100;
1097 idval = nil;
1098 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);
1099 testassert(state == 1);
1100 testassert(idval == ID_RESULT);
1101 testassert(sup_st.receiver == sub);
1102 testassert(sup_st.super_class == object_getClass(sub));
1103
1104 state = 100;
1105 stretval = zero;
1106 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);
1107 testassert(state == 3);
1108 testassert(stret_equal(stretval, STRET_RESULT));
1109 testassert(sup_st.receiver == sub);
1110 testassert(sup_st.super_class == object_getClass(sub));
1111 #endif
1112
1113 #if __OBJC2__
1114 // Debug messengers.
1115 state = 0;
1116 idmsg = (typeof(idmsg))objc_msgSend_debug;
1117 idval = nil;
1118 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);
1119 testassert(state == 101);
1120 testassert(idval == ID_RESULT);
1121
1122 state = 0;
1123 llmsg = (typeof(llmsg))objc_msgSend_debug;
1124 llval = 0;
1125 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);
1126 testassert(state == 102);
1127 testassert(llval == LL_RESULT);
1128
1129 state = 0;
1130 stretmsg = (typeof(stretmsg))objc_msgSend_stret_debug;
1131 stretval = zero;
1132 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);
1133 testassert(state == 103);
1134 testassert(stret_equal(stretval, STRET_RESULT));
1135
1136 state = 100;
1137 sup_st.receiver = sub;
1138 sup_st.super_class = object_getClass(sub);
1139 idmsgsuper = (typeof(idmsgsuper))objc_msgSendSuper2_debug;
1140 idval = nil;
1141 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);
1142 testassert(state == 1);
1143 testassert(idval == ID_RESULT);
1144
1145 state = 100;
1146 sup_st.receiver = sub;
1147 sup_st.super_class = object_getClass(sub);
1148 stretmsgsuper = (typeof(stretmsgsuper))objc_msgSendSuper2_stret_debug;
1149 stretval = zero;
1150 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);
1151 testassert(state == 3);
1152 testassert(stret_equal(stretval, STRET_RESULT));
1153
1154 #if __i386__
1155 state = 0;
1156 fpmsg = (typeof(fpmsg))objc_msgSend_fpret_debug;
1157 fpval = 0;
1158 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);
1159 testassert(state == 104);
1160 testassert(fpval == FP_RESULT);
1161 #endif
1162 #if __x86_64__
1163 state = 0;
1164 lfpmsg = (typeof(lfpmsg))objc_msgSend_fpret_debug;
1165 lfpval = 0;
1166 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);
1167 testassert(state == 105);
1168 testassert(lfpval == LFP_RESULT);
1169
1170 // fixme fp2ret
1171 #endif
1172
1173 // debug messengers
1174 #endif
1175
1176
1177 #if __x86_64__ && !__has_feature(objc_arc)
1178 // DWARF unwind tables
1179 // Not for ARC because the extra RR calls hit the traps at the wrong times
1180
1181 // install exception handler
1182 struct sigaction act;
1183 act.sa_sigaction = sigtrap;
1184 act.sa_mask = 0;
1185 act.sa_flags = SA_SIGINFO;
1186 sigaction(SIGTRAP, &act, NULL);
1187
1188 // use _nop methods because other methods make more calls
1189 // which can die in the trapped messenger
1190
1191 test_dw("objc_msgSend", sub,tagged,@selector(idret_nop));
1192 test_dw("objc_msgSend_fixup", sub,tagged,@selector(idret_nop));
1193 test_dw("objc_msgSend_stret", sub,tagged,@selector(stret_nop));
1194 test_dw("objc_msgSend_stret_fixup", sub,tagged,@selector(stret_nop));
1195 test_dw("objc_msgSend_fpret", sub,tagged,@selector(fpret_nop));
1196 test_dw("objc_msgSend_fpret_fixup", sub,tagged,@selector(fpret_nop));
1197 // fixme fp2ret
1198 test_dw("objc_msgSendSuper", sub,tagged,@selector(idret_nop));
1199 test_dw("objc_msgSendSuper2", sub,tagged,@selector(idret_nop));
1200 test_dw("objc_msgSendSuper2_fixup", sub,tagged,@selector(idret_nop));
1201 test_dw("objc_msgSendSuper_stret", sub,tagged,@selector(stret_nop));
1202 test_dw("objc_msgSendSuper2_stret", sub,tagged,@selector(stret_nop));
1203 test_dw("objc_msgSendSuper2_stret_fixup", sub,tagged,@selector(stret_nop));
1204
1205 // DWARF unwind tables
1206 #endif
1207 } POP_POOL;
1208 succeed(__FILE__);
1209 }
1210
1211 #endif