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