[arm64] Resurrect inlined fast tls
[mono.git] / mono / utils / mono-tls.c
1 /*
2  * mono-tls.c: Low-level TLS support
3  *
4  * Thread local variables that are accessed both from native and managed code
5  * are defined here and should be accessed only through this APIs
6  *
7  * Copyright 2013 Xamarin, Inc (http://www.xamarin.com)
8  */
9
10 #include <config.h>
11 #include <mono/utils/mach-support.h>
12
13 #include "mono-tls.h"
14
15 /*
16  * On all platforms we should be able to use either __thread or pthread/TlsGetValue.
17  * Certain platforms will support fast tls only when using one of the thread local
18  * storage backends. By default this is __thread if we have HAVE_KW_THREAD defined.
19  *
20  * By default all platforms will call into these native getters whenever they need
21  * to get a tls value. On certain platforms we can try to be faster than this and
22  * avoid the call. We call this fast tls and each platform defines its own way to
23  * achieve this. For this, a platform has to define MONO_ARCH_HAVE_INLINED_TLS,
24  * and provide alternative getters/setters for a MonoTlsKey. In order to have fast
25  * getter/setters, the platform has to declare a way to fetch an internal offset
26  * (MONO_THREAD_VAR_OFFSET) which is stored here, and in the arch specific file
27  * probe the system to see if we can use the offset initialized here. If these
28  * run-time checks don't succeed we just use the fallbacks.
29  *
30  * In case we would wish to provide fast inlined tls for aot code, we would need
31  * to be sure that, at run-time, these two platform checks would never fail
32  * otherwise the tls getter/setters that we emitted would not work. Normally,
33  * there is little incentive to support this since tls access is most common in
34  * wrappers and managed allocators, both of which are not aot-ed by default.
35  * So far, we never supported inlined fast tls on full-aot systems.
36  */
37 #ifdef HAVE_KW_THREAD
38 #define USE_KW_THREAD
39 #endif
40
41 #ifdef USE_KW_THREAD
42
43 /* tls attribute */
44 #if HAVE_TLS_MODEL_ATTR
45
46 #if defined(__PIC__) && !defined(PIC)
47 /*
48  * Must be compiling -fPIE, for executables.  Build PIC
49  * but with initial-exec.
50  * http://bugs.gentoo.org/show_bug.cgi?id=165547
51  */
52 #define PIC
53 #define PIC_INITIAL_EXEC
54 #endif
55
56 /*
57  * Define this if you want a faster libmono, which cannot be loaded dynamically as a
58  * module.
59  */
60 //#define PIC_INITIAL_EXEC
61
62 #if defined(PIC)
63
64 #ifdef PIC_INITIAL_EXEC
65 #define MONO_TLS_FAST __attribute__((tls_model("initial-exec")))
66 #else
67 #if defined (__powerpc__)
68 /* local dynamic requires a call to __tls_get_addr to look up the
69    TLS block address via the Dynamic Thread Vector. In this case Thread
70    Pointer relative offsets can't be used as this modules TLS was
71    allocated separately (none contiguoiusly) from the initial TLS
72    block.
73
74    For now we will disable this. */
75 #define MONO_TLS_FAST
76 #else
77 #define MONO_TLS_FAST __attribute__((tls_model("local-dynamic")))
78 #endif
79 #endif
80
81 #else
82
83 #define MONO_TLS_FAST __attribute__((tls_model("local-exec")))
84
85 #endif
86
87 #else
88 #define MONO_TLS_FAST
89 #endif
90
91 /* Runtime offset detection */
92 #if defined(TARGET_AMD64) && !defined(TARGET_MACH) && !defined(HOST_WIN32) /* __thread likely not tested on mac/win */
93
94 #if defined(PIC)
95 // This only works if libmono is linked into the application
96 #define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo;  __asm ("movq " #var "@GOTTPOFF(%%rip), %0" : "=r" (foo)); offset = foo; } while (0)
97 #else
98 #define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo;  __asm ("movq $" #var "@TPOFF, %0" : "=r" (foo)); offset = foo; } while (0)
99 #endif
100
101 #elif defined(TARGET_X86) && !defined(TARGET_MACH) && !defined(HOST_WIN32) && defined(__GNUC__)
102
103 #if defined(PIC)
104 #define MONO_THREAD_VAR_OFFSET(var,offset) do { int tmp; __asm ("call 1f; 1: popl %0; addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %0; movl " #var "@gotntpoff(%0), %1" : "=r" (tmp), "=r" (offset)); } while (0)
105 #else
106 #define MONO_THREAD_VAR_OFFSET(var,offset) __asm ("movl $" #var "@ntpoff, %0" : "=r" (offset))
107 #endif
108
109 #elif defined(TARGET_ARM64) && !defined(PIC)
110
111 #define MONO_THREAD_VAR_OFFSET(var,offset) \
112         __asm ( "mov %0, #0\n add %0, %0, #:tprel_hi12:" #var "\n add %0, %0, #:tprel_lo12_nc:" #var "\n" \
113                 : "=r" (offset))
114
115 #else
116
117 #define MONO_THREAD_VAR_OFFSET(var,offset) (offset) = -1
118
119 #endif
120
121 /* Tls variables for each MonoTlsKey */
122
123 static __thread gpointer mono_tls_thread MONO_TLS_FAST;
124 static __thread gpointer mono_tls_jit_tls MONO_TLS_FAST;
125 static __thread gpointer mono_tls_domain MONO_TLS_FAST;
126 static __thread gpointer mono_tls_lmf MONO_TLS_FAST;
127 static __thread gpointer mono_tls_sgen_thread_info MONO_TLS_FAST;
128 static __thread gpointer mono_tls_lmf_addr MONO_TLS_FAST;
129
130 #else
131
132 #if defined(TARGET_AMD64) && (defined(TARGET_MACH) || defined(HOST_WIN32))
133 #define MONO_THREAD_VAR_OFFSET(key,offset) (offset) = (gint32)key
134 #elif defined(TARGET_X86) && (defined(TARGET_MACH) || defined(HOST_WIN32))
135 #define MONO_THREAD_VAR_OFFSET(key,offset) (offset) = (gint32)key
136 #else
137 #define MONO_THREAD_VAR_OFFSET(var,offset) (offset) = -1
138 #endif
139
140 static MonoNativeTlsKey mono_tls_key_thread;
141 static MonoNativeTlsKey mono_tls_key_jit_tls;
142 static MonoNativeTlsKey mono_tls_key_domain;
143 static MonoNativeTlsKey mono_tls_key_lmf;
144 static MonoNativeTlsKey mono_tls_key_sgen_thread_info;
145 static MonoNativeTlsKey mono_tls_key_lmf_addr;
146
147 #endif
148
149 static gint32 tls_offsets [TLS_KEY_NUM];
150
151 #ifdef USE_KW_THREAD
152 #define MONO_TLS_GET_VALUE(tls_var,tls_key) (tls_var)
153 #define MONO_TLS_SET_VALUE(tls_var,tls_key,value) (tls_var = value)
154 #else
155 #define MONO_TLS_GET_VALUE(tls_var,tls_key) (mono_native_tls_get_value (tls_key))
156 #define MONO_TLS_SET_VALUE(tls_var,tls_key,value) (mono_native_tls_set_value (tls_key, value))
157 #endif
158
159 void
160 mono_tls_init_gc_keys (void)
161 {
162 #ifdef USE_KW_THREAD
163         MONO_THREAD_VAR_OFFSET (mono_tls_sgen_thread_info, tls_offsets [TLS_KEY_SGEN_THREAD_INFO]);
164 #else
165         mono_native_tls_alloc (&mono_tls_key_sgen_thread_info, NULL);
166         MONO_THREAD_VAR_OFFSET (mono_tls_key_sgen_thread_info, tls_offsets [TLS_KEY_SGEN_THREAD_INFO]);
167 #endif
168 }
169
170 void
171 mono_tls_init_runtime_keys (void)
172 {
173 #ifdef USE_KW_THREAD
174         MONO_THREAD_VAR_OFFSET (mono_tls_thread, tls_offsets [TLS_KEY_THREAD]);
175         MONO_THREAD_VAR_OFFSET (mono_tls_jit_tls, tls_offsets [TLS_KEY_JIT_TLS]);
176         MONO_THREAD_VAR_OFFSET (mono_tls_domain, tls_offsets [TLS_KEY_DOMAIN]);
177         MONO_THREAD_VAR_OFFSET (mono_tls_lmf, tls_offsets [TLS_KEY_LMF]);
178         MONO_THREAD_VAR_OFFSET (mono_tls_lmf_addr, tls_offsets [TLS_KEY_LMF_ADDR]);
179 #else
180         mono_native_tls_alloc (&mono_tls_key_thread, NULL);
181         MONO_THREAD_VAR_OFFSET (mono_tls_key_thread, tls_offsets [TLS_KEY_THREAD]);
182         mono_native_tls_alloc (&mono_tls_key_jit_tls, NULL);
183         MONO_THREAD_VAR_OFFSET (mono_tls_key_jit_tls, tls_offsets [TLS_KEY_JIT_TLS]);
184         mono_native_tls_alloc (&mono_tls_key_domain, NULL);
185         MONO_THREAD_VAR_OFFSET (mono_tls_key_domain, tls_offsets [TLS_KEY_DOMAIN]);
186         mono_native_tls_alloc (&mono_tls_key_lmf, NULL);
187         MONO_THREAD_VAR_OFFSET (mono_tls_key_lmf, tls_offsets [TLS_KEY_LMF]);
188         mono_native_tls_alloc (&mono_tls_key_lmf_addr, NULL);
189         MONO_THREAD_VAR_OFFSET (mono_tls_key_lmf_addr, tls_offsets [TLS_KEY_LMF_ADDR]);
190 #endif
191 }
192
193 void
194 mono_tls_free_keys (void)
195 {
196 #ifndef USE_KW_THREAD
197         mono_native_tls_free (mono_tls_key_thread);
198         mono_native_tls_free (mono_tls_key_jit_tls);
199         mono_native_tls_free (mono_tls_key_domain);
200         mono_native_tls_free (mono_tls_key_lmf);
201         mono_native_tls_free (mono_tls_key_sgen_thread_info);
202         mono_native_tls_free (mono_tls_key_lmf_addr);
203 #endif
204 }
205
206
207 /*
208  * Gets the tls offset associated with the key. This offset is set at key
209  * initialization (at runtime). Certain targets can implement computing
210  * this offset and using it at runtime for fast inlined tls access.
211  */
212 gint32
213 mono_tls_get_tls_offset (MonoTlsKey key)
214 {
215         g_assert (tls_offsets [key]);
216         return tls_offsets [key];
217 }
218
219 /*
220  * Returns the getter (gpointer (*)(void)) for the mono tls key.
221  * Managed code will always get the value by calling this getter.
222  */
223 gpointer
224 mono_tls_get_tls_getter (MonoTlsKey key, gboolean name)
225 {
226         switch (key) {
227         case TLS_KEY_THREAD:
228                 return name ? (gpointer)"mono_tls_get_thread" : (gpointer)mono_tls_get_thread;
229         case TLS_KEY_JIT_TLS:
230                 return name ? (gpointer)"mono_tls_get_jit_tls" : (gpointer)mono_tls_get_jit_tls;
231         case TLS_KEY_DOMAIN:
232                 return name ? (gpointer)"mono_tls_get_domain" : (gpointer)mono_tls_get_domain;
233         case TLS_KEY_LMF:
234                 return name ? (gpointer)"mono_tls_get_lmf" : (gpointer)mono_tls_get_lmf;
235         case TLS_KEY_SGEN_THREAD_INFO:
236                 return name ? (gpointer)"mono_tls_get_sgen_thread_info" : (gpointer)mono_tls_get_sgen_thread_info;
237         case TLS_KEY_LMF_ADDR:
238                 return name ? (gpointer)"mono_tls_get_lmf_addr" : (gpointer)mono_tls_get_lmf_addr;
239         }
240         g_assert_not_reached ();
241         return NULL;
242 }
243
244 /* Returns the setter (void (*)(gpointer)) for the mono tls key */
245 gpointer
246 mono_tls_get_tls_setter (MonoTlsKey key, gboolean name)
247 {
248         switch (key) {
249         case TLS_KEY_THREAD:
250                 return name ? (gpointer)"mono_tls_set_thread" : (gpointer)mono_tls_set_thread;
251         case TLS_KEY_JIT_TLS:
252                 return name ? (gpointer)"mono_tls_set_jit_tls" : (gpointer)mono_tls_set_jit_tls;
253         case TLS_KEY_DOMAIN:
254                 return name ? (gpointer)"mono_tls_set_domain" : (gpointer)mono_tls_set_domain;
255         case TLS_KEY_LMF:
256                 return name ? (gpointer)"mono_tls_set_lmf" : (gpointer)mono_tls_set_lmf;
257         case TLS_KEY_SGEN_THREAD_INFO:
258                 return name ? (gpointer)"mono_tls_set_sgen_thread_info" : (gpointer)mono_tls_set_sgen_thread_info;
259         case TLS_KEY_LMF_ADDR:
260                 return name ? (gpointer)"mono_tls_set_lmf_addr" : (gpointer)mono_tls_set_lmf_addr;
261         }
262         g_assert_not_reached ();
263         return NULL;
264 }
265
266 gpointer
267 mono_tls_get_tls_addr (MonoTlsKey key)
268 {
269         if (key == TLS_KEY_LMF) {
270 #if defined(USE_KW_THREAD)
271                 return &mono_tls_lmf;
272 #elif defined(TARGET_MACH)
273                 return mono_mach_get_tls_address_from_thread (pthread_self (), mono_tls_key_lmf);
274 #endif
275         }
276         /* Implement if we ever need for other targets/keys */
277         g_assert_not_reached ();
278         return NULL;
279 }
280
281 /* Getters for each tls key */
282 gpointer mono_tls_get_thread (void)
283 {
284         return MONO_TLS_GET_VALUE (mono_tls_thread, mono_tls_key_thread);
285 }
286
287 gpointer mono_tls_get_jit_tls (void)
288 {
289         return MONO_TLS_GET_VALUE (mono_tls_jit_tls, mono_tls_key_jit_tls);
290 }
291
292 gpointer mono_tls_get_domain (void)
293 {
294         return MONO_TLS_GET_VALUE (mono_tls_domain, mono_tls_key_domain);
295 }
296
297 gpointer mono_tls_get_lmf (void)
298 {
299         return MONO_TLS_GET_VALUE (mono_tls_lmf, mono_tls_key_lmf);
300 }
301
302 gpointer mono_tls_get_sgen_thread_info (void)
303 {
304         return MONO_TLS_GET_VALUE (mono_tls_sgen_thread_info, mono_tls_key_sgen_thread_info);
305 }
306
307 gpointer mono_tls_get_lmf_addr (void)
308 {
309         return MONO_TLS_GET_VALUE (mono_tls_lmf_addr, mono_tls_key_lmf_addr);
310 }
311
312 /* Setters for each tls key */
313 void mono_tls_set_thread (gpointer value)
314 {
315         MONO_TLS_SET_VALUE (mono_tls_thread, mono_tls_key_thread, value);
316 }
317
318 void mono_tls_set_jit_tls (gpointer value)
319 {
320         MONO_TLS_SET_VALUE (mono_tls_jit_tls, mono_tls_key_jit_tls, value);
321 }
322
323 void mono_tls_set_domain (gpointer value)
324 {
325         MONO_TLS_SET_VALUE (mono_tls_domain, mono_tls_key_domain, value);
326 }
327
328 void mono_tls_set_lmf (gpointer value)
329 {
330         MONO_TLS_SET_VALUE (mono_tls_lmf, mono_tls_key_lmf, value);
331 }
332
333 void mono_tls_set_sgen_thread_info (gpointer value)
334 {
335         MONO_TLS_SET_VALUE (mono_tls_sgen_thread_info, mono_tls_key_sgen_thread_info, value);
336 }
337
338 void mono_tls_set_lmf_addr (gpointer value)
339 {
340         MONO_TLS_SET_VALUE (mono_tls_lmf_addr, mono_tls_key_lmf_addr, value);
341 }