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