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