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