]>
Commit | Line | Data |
---|---|---|
1807f628 A |
1 | // TEST_CONFIG OS=macosx,iphoneos,tvos,watchos |
2 | ||
3 | // This test checks that objc_msgSend's recovery path works correctly. | |
4 | // It continuously runs msgSend on some background threads, then | |
5 | // triggers the recovery path constantly as a stress test. | |
6 | ||
7 | #include "test.h" | |
8 | #include "testroot.i" | |
9 | #include <dispatch/dispatch.h> | |
10 | ||
11 | struct Big { | |
12 | uintptr_t a, b, c, d, e, f, g; | |
13 | }; | |
14 | ||
15 | @interface C1: TestRoot | |
16 | @end | |
17 | @implementation C1 | |
18 | - (id)idret { return nil; } | |
19 | - (double)fpret { return 0.0; } | |
20 | - (long double)lfpret { return 0.0; } | |
21 | - (struct Big)stret { return (struct Big){}; } | |
22 | @end | |
23 | ||
24 | @interface C2: C1 | |
25 | @end | |
26 | @implementation C2 | |
27 | - (id)idret { return [super idret]; } | |
28 | - (double)fpret { return [super fpret]; } | |
29 | - (long double)lfpret { return [super lfpret]; } | |
30 | - (struct Big)stret { return [super stret]; } | |
31 | @end | |
32 | ||
33 | EXTERN_C kern_return_t task_restartable_ranges_synchronize(task_t task); | |
34 | ||
35 | EXTERN_C void sendWithMsgLookup(id self, SEL _cmd); | |
36 | ||
37 | #if defined(__arm64__) && !__has_feature(ptrauth_calls) | |
38 | asm( | |
39 | "_sendWithMsgLookup: \n" | |
40 | " stp fp, lr, [sp, #-16]! \n" | |
41 | " mov fp, sp \n" | |
42 | " bl _objc_msgLookup \n" | |
43 | " mov sp, fp \n" | |
44 | " ldp fp, lr, [sp], #16 \n" | |
45 | " br x17 \n" | |
46 | ); | |
47 | #elif defined(__x86_64__) | |
48 | asm( | |
49 | "_sendWithMsgLookup: \n" | |
50 | " pushq %rbp \n" | |
51 | " movq %rsp, %rbp \n" | |
52 | " callq _objc_msgLookup \n" | |
53 | " popq %rbp \n" | |
54 | " jmpq *%r11 \n" | |
55 | ); | |
56 | #else | |
57 | // Just skip it. | |
58 | void sendWithMsgLookup(id self __unused, SEL _cmd __unused) {} | |
59 | #endif | |
60 | ||
61 | int main() { | |
62 | id obj = [C2 new]; | |
63 | for(int i = 0; i < 2; i++) { | |
64 | dispatch_async(dispatch_get_global_queue(0, 0), ^{ | |
65 | while(1) { | |
66 | [obj idret]; | |
67 | [obj fpret]; | |
68 | [obj lfpret]; | |
69 | [obj stret]; | |
70 | sendWithMsgLookup(obj, @selector(idret)); | |
71 | } | |
72 | }); | |
73 | } | |
74 | for(int i = 0; i < 1000000; i++) { | |
75 | task_restartable_ranges_synchronize(mach_task_self());; | |
76 | } | |
77 | succeed(__FILE__); | |
78 | } |