]> git.saurik.com Git - apple/objc4.git/blob - test/msgSend.m
fd7153913f3bb9237dc470b019e033a24cb50d56
[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 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 NIL_RECEIVER;
85 id ID_RESULT;
86 long long LL_RESULT = __LONG_LONG_MAX__ - 2LL*__INT_MAX__;
87 double FP_RESULT = __DBL_MIN__ + __DBL_EPSILON__;
88 long double LFP_RESULT = __LDBL_MIN__ + __LDBL_EPSILON__;
89 // STRET_RESULT in test.h
90
91 static 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
428 bool caught = false;
429 uintptr_t clobbered;
430
431 uintptr_t r12 = 0;
432 uintptr_t r13 = 0;
433 uintptr_t r14 = 0;
434 uintptr_t r15 = 0;
435 uintptr_t rbx = 0;
436 uintptr_t rbp = 0;
437 uintptr_t rsp = 0;
438 uintptr_t rip = 0;
439
440 void 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
500 void 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
515 uint8_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
526 uint8_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
532 void unclobber(void *fn, uintptr_t offset, uint8_t oldvalue)
533 {
534 set((uintptr_t)fn + offset, oldvalue);
535 }
536
537 __BEGIN_DECLS
538 extern void callit(void *obj, void *sel, void *fn);
539 extern 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
580 uintptr_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
633 void CALLIT(void *o, void *sel_arg, SEL s, void *f) __attribute__((noinline));
634 void 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)
655 void 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
741 void 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
826 int 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