[runtime] Fix DISABLE_REFLECTION_EMIT build.
[mono.git] / mono / utils / mono-tls.c
1 /**
2  * \file
3  * Low-level TLS support
4  *
5  * Thread local variables that are accessed both from native and managed code
6  * are defined here and should be accessed only through this APIs
7  *
8  * Copyright 2013 Xamarin, Inc (http://www.xamarin.com)
9  */
10
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
38 #ifdef USE_KW_THREAD
39
40 /* tls attribute */
41 #if HAVE_TLS_MODEL_ATTR
42
43 #if defined(__PIC__) && !defined(PIC)
44 /*
45  * Must be compiling -fPIE, for executables.  Build PIC
46  * but with initial-exec.
47  * http://bugs.gentoo.org/show_bug.cgi?id=165547
48  */
49 #define PIC
50 #define PIC_INITIAL_EXEC
51 #endif
52
53 /*
54  * Define this if you want a faster libmono, which cannot be loaded dynamically as a
55  * module.
56  */
57 //#define PIC_INITIAL_EXEC
58
59 #if defined(PIC)
60
61 #ifdef PIC_INITIAL_EXEC
62 #define MONO_TLS_FAST __attribute__ ((__tls_model__("initial-exec")))
63 #else
64 #if defined (__powerpc__)
65 /* local dynamic requires a call to __tls_get_addr to look up the
66    TLS block address via the Dynamic Thread Vector. In this case Thread
67    Pointer relative offsets can't be used as this modules TLS was
68    allocated separately (none contiguoiusly) from the initial TLS
69    block.
70
71    For now we will disable this. */
72 #define MONO_TLS_FAST
73 #else
74 #define MONO_TLS_FAST __attribute__ ((__tls_model__("local-dynamic")))
75 #endif
76 #endif
77
78 #else
79
80 #define MONO_TLS_FAST __attribute__ ((__tls_model__("local-exec")))
81
82 #endif
83
84 #else
85 #define MONO_TLS_FAST
86 #endif
87
88 /* Runtime offset detection */
89 #if defined(TARGET_AMD64) && !defined(TARGET_MACH) && !defined(HOST_WIN32) /* __thread likely not tested on mac/win */
90
91 #if defined(PIC)
92 // This only works if libmono is linked into the application
93 #define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo;  __asm ("movq " #var "@GOTTPOFF(%%rip), %0" : "=r" (foo)); offset = foo; } while (0)
94 #else
95 #define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo;  __asm ("movq $" #var "@TPOFF, %0" : "=r" (foo)); offset = foo; } while (0)
96 #endif
97
98 #elif defined(TARGET_X86) && !defined(TARGET_MACH) && !defined(HOST_WIN32) && defined(__GNUC__)
99
100 #if defined(PIC)
101 #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)
102 #else
103 #define MONO_THREAD_VAR_OFFSET(var,offset) __asm ("movl $" #var "@ntpoff, %0" : "=r" (offset))
104 #endif
105
106 #elif defined(TARGET_ARM64) && !defined(PIC)
107
108 #define MONO_THREAD_VAR_OFFSET(var,offset) \
109         __asm ( "mov %0, #0\n add %0, %0, #:tprel_hi12:" #var "\n add %0, %0, #:tprel_lo12_nc:" #var "\n" \
110                 : "=r" (offset))
111
112 #elif defined(TARGET_ARM) && defined(__ARM_EABI__) && !defined(PIC)
113
114 #define MONO_THREAD_VAR_OFFSET(var,offset) __asm ("     ldr     %0, 1f; b 2f; 1: .word " #var "(tpoff); 2:" : "=r" (offset))
115
116 #elif defined(TARGET_S390X)
117 # if defined(__PIC__)
118 #  if !defined(__PIE__)
119 // This only works if libmono is linked into the application
120 #   define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo;                                 \
121                                                 __asm__ ("basr  %%r1,0\n\t"                     \
122                                                          "j     0f\n\t"                         \
123                                                          ".quad " #var "@TLSGD\n"               \
124                                                          "0:\n\t"                               \
125                                                          "lg    %%r2,4(%%r1)\n\t"               \
126                                                          "brasl %%r14,__tls_get_offset@PLT:tls_gdcall:"#var"\n\t" \
127                                                          "lgr   %0,%%r2\n\t"                    \
128                                                         : "=r" (foo) :                          \
129                                                         : "1", "2", "14", "cc");                \
130                                                 offset = foo; } while (0)
131 #  elif __PIE__ == 1
132 #   define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo;                                         \
133                                                 __asm__ ("lg    %0," #var "@GOTNTPOFF(%%r12)\n\t"       \
134                                                          : "=r" (foo));                                 \
135                                                 offset = foo; } while (0)
136 #  elif __PIE__ == 2
137 #   define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo;                                 \
138                                                 __asm__ ("larl  %%r1," #var "@INDNTPOFF\n\t"    \
139                                                          "lg    %0,0(%%r1)\n\t"                 \
140                                                          : "=r" (foo) :                         \
141                                                          : "1", "cc");                          \
142                                                 offset = foo; } while (0)
143 #  endif
144 # else
145 #  define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo;                          \
146                                                 __asm__ ("basr  %%r1,0\n\t"             \
147                                                          "j     0f\n\t"                 \
148                                                          ".quad " #var "@NTPOFF\n"      \
149                                                          "0:\n\t"                       \
150                                                          "lg    %0,4(%%r1)\n\t"         \
151                                                         : "=r" (foo) : : "1");          \
152                                                 offset = foo; } while (0)
153 # endif
154 #else
155
156 #define MONO_THREAD_VAR_OFFSET(var,offset) (offset) = -1
157
158 #endif
159
160 /* Tls variables for each MonoTlsKey */
161
162 static __thread gpointer mono_tls_thread MONO_TLS_FAST;
163 static __thread gpointer mono_tls_jit_tls MONO_TLS_FAST;
164 static __thread gpointer mono_tls_domain MONO_TLS_FAST;
165 static __thread gpointer mono_tls_lmf MONO_TLS_FAST;
166 static __thread gpointer mono_tls_sgen_thread_info MONO_TLS_FAST;
167 static __thread gpointer mono_tls_lmf_addr MONO_TLS_FAST;
168
169 #else
170
171 #if defined(TARGET_AMD64) && (defined(TARGET_MACH) || defined(HOST_WIN32))
172 #define MONO_THREAD_VAR_OFFSET(key,offset) (offset) = (gint32)key
173 #elif defined(TARGET_X86) && (defined(TARGET_MACH) || defined(HOST_WIN32))
174 #define MONO_THREAD_VAR_OFFSET(key,offset) (offset) = (gint32)key
175 #else
176 #define MONO_THREAD_VAR_OFFSET(var,offset) (offset) = -1
177 #endif
178
179 static MonoNativeTlsKey mono_tls_key_thread;
180 static MonoNativeTlsKey mono_tls_key_jit_tls;
181 static MonoNativeTlsKey mono_tls_key_domain;
182 static MonoNativeTlsKey mono_tls_key_sgen_thread_info;
183 static MonoNativeTlsKey mono_tls_key_lmf_addr;
184
185 #endif
186
187 static gint32 tls_offsets [TLS_KEY_NUM];
188
189 #ifdef USE_KW_THREAD
190 #define MONO_TLS_GET_VALUE(tls_var,tls_key) (tls_var)
191 #define MONO_TLS_SET_VALUE(tls_var,tls_key,value) (tls_var = value)
192 #else
193 #define MONO_TLS_GET_VALUE(tls_var,tls_key) (mono_native_tls_get_value (tls_key))
194 #define MONO_TLS_SET_VALUE(tls_var,tls_key,value) (mono_native_tls_set_value (tls_key, value))
195 #endif
196
197 void
198 mono_tls_init_gc_keys (void)
199 {
200 #ifdef USE_KW_THREAD
201         MONO_THREAD_VAR_OFFSET (mono_tls_sgen_thread_info, tls_offsets [TLS_KEY_SGEN_THREAD_INFO]);
202 #else
203         mono_native_tls_alloc (&mono_tls_key_sgen_thread_info, NULL);
204         MONO_THREAD_VAR_OFFSET (mono_tls_key_sgen_thread_info, tls_offsets [TLS_KEY_SGEN_THREAD_INFO]);
205 #endif
206 }
207
208 void
209 mono_tls_init_runtime_keys (void)
210 {
211 #ifdef USE_KW_THREAD
212         MONO_THREAD_VAR_OFFSET (mono_tls_thread, tls_offsets [TLS_KEY_THREAD]);
213         MONO_THREAD_VAR_OFFSET (mono_tls_jit_tls, tls_offsets [TLS_KEY_JIT_TLS]);
214         MONO_THREAD_VAR_OFFSET (mono_tls_domain, tls_offsets [TLS_KEY_DOMAIN]);
215         MONO_THREAD_VAR_OFFSET (mono_tls_lmf_addr, tls_offsets [TLS_KEY_LMF_ADDR]);
216 #else
217         mono_native_tls_alloc (&mono_tls_key_thread, NULL);
218         MONO_THREAD_VAR_OFFSET (mono_tls_key_thread, tls_offsets [TLS_KEY_THREAD]);
219         mono_native_tls_alloc (&mono_tls_key_jit_tls, NULL);
220         MONO_THREAD_VAR_OFFSET (mono_tls_key_jit_tls, tls_offsets [TLS_KEY_JIT_TLS]);
221         mono_native_tls_alloc (&mono_tls_key_domain, NULL);
222         MONO_THREAD_VAR_OFFSET (mono_tls_key_domain, tls_offsets [TLS_KEY_DOMAIN]);
223         mono_native_tls_alloc (&mono_tls_key_lmf_addr, NULL);
224         MONO_THREAD_VAR_OFFSET (mono_tls_key_lmf_addr, tls_offsets [TLS_KEY_LMF_ADDR]);
225 #endif
226 }
227
228 void
229 mono_tls_free_keys (void)
230 {
231 #ifndef USE_KW_THREAD
232         mono_native_tls_free (mono_tls_key_thread);
233         mono_native_tls_free (mono_tls_key_jit_tls);
234         mono_native_tls_free (mono_tls_key_domain);
235         mono_native_tls_free (mono_tls_key_sgen_thread_info);
236         mono_native_tls_free (mono_tls_key_lmf_addr);
237 #endif
238 }
239
240
241 /*
242  * Gets the tls offset associated with the key. This offset is set at key
243  * initialization (at runtime). Certain targets can implement computing
244  * this offset and using it at runtime for fast inlined tls access.
245  */
246 gint32
247 mono_tls_get_tls_offset (MonoTlsKey key)
248 {
249         g_assert (tls_offsets [key]);
250         return tls_offsets [key];
251 }
252
253 /*
254  * Returns the getter (gpointer (*)(void)) for the mono tls key.
255  * Managed code will always get the value by calling this getter.
256  */
257 gpointer
258 mono_tls_get_tls_getter (MonoTlsKey key, gboolean name)
259 {
260         switch (key) {
261         case TLS_KEY_THREAD:
262                 return name ? (gpointer)"mono_tls_get_thread" : (gpointer)mono_tls_get_thread;
263         case TLS_KEY_JIT_TLS:
264                 return name ? (gpointer)"mono_tls_get_jit_tls" : (gpointer)mono_tls_get_jit_tls;
265         case TLS_KEY_DOMAIN:
266                 return name ? (gpointer)"mono_tls_get_domain" : (gpointer)mono_tls_get_domain;
267         case TLS_KEY_SGEN_THREAD_INFO:
268                 return name ? (gpointer)"mono_tls_get_sgen_thread_info" : (gpointer)mono_tls_get_sgen_thread_info;
269         case TLS_KEY_LMF_ADDR:
270                 return name ? (gpointer)"mono_tls_get_lmf_addr" : (gpointer)mono_tls_get_lmf_addr;
271         }
272         g_assert_not_reached ();
273         return NULL;
274 }
275
276 /* Returns the setter (void (*)(gpointer)) for the mono tls key */
277 gpointer
278 mono_tls_get_tls_setter (MonoTlsKey key, gboolean name)
279 {
280         switch (key) {
281         case TLS_KEY_THREAD:
282                 return name ? (gpointer)"mono_tls_set_thread" : (gpointer)mono_tls_set_thread;
283         case TLS_KEY_JIT_TLS:
284                 return name ? (gpointer)"mono_tls_set_jit_tls" : (gpointer)mono_tls_set_jit_tls;
285         case TLS_KEY_DOMAIN:
286                 return name ? (gpointer)"mono_tls_set_domain" : (gpointer)mono_tls_set_domain;
287         case TLS_KEY_SGEN_THREAD_INFO:
288                 return name ? (gpointer)"mono_tls_set_sgen_thread_info" : (gpointer)mono_tls_set_sgen_thread_info;
289         case TLS_KEY_LMF_ADDR:
290                 return name ? (gpointer)"mono_tls_set_lmf_addr" : (gpointer)mono_tls_set_lmf_addr;
291         }
292         g_assert_not_reached ();
293         return NULL;
294 }
295
296 /* Getters for each tls key */
297 gpointer mono_tls_get_thread (void)
298 {
299         return MONO_TLS_GET_VALUE (mono_tls_thread, mono_tls_key_thread);
300 }
301
302 gpointer mono_tls_get_jit_tls (void)
303 {
304         return MONO_TLS_GET_VALUE (mono_tls_jit_tls, mono_tls_key_jit_tls);
305 }
306
307 gpointer mono_tls_get_domain (void)
308 {
309         return MONO_TLS_GET_VALUE (mono_tls_domain, mono_tls_key_domain);
310 }
311
312 gpointer mono_tls_get_sgen_thread_info (void)
313 {
314         return MONO_TLS_GET_VALUE (mono_tls_sgen_thread_info, mono_tls_key_sgen_thread_info);
315 }
316
317 gpointer mono_tls_get_lmf_addr (void)
318 {
319         return MONO_TLS_GET_VALUE (mono_tls_lmf_addr, mono_tls_key_lmf_addr);
320 }
321
322 /* Setters for each tls key */
323 void mono_tls_set_thread (gpointer value)
324 {
325         MONO_TLS_SET_VALUE (mono_tls_thread, mono_tls_key_thread, value);
326 }
327
328 void mono_tls_set_jit_tls (gpointer value)
329 {
330         MONO_TLS_SET_VALUE (mono_tls_jit_tls, mono_tls_key_jit_tls, value);
331 }
332
333 void mono_tls_set_domain (gpointer value)
334 {
335         MONO_TLS_SET_VALUE (mono_tls_domain, mono_tls_key_domain, value);
336 }
337
338 void mono_tls_set_sgen_thread_info (gpointer value)
339 {
340         MONO_TLS_SET_VALUE (mono_tls_sgen_thread_info, mono_tls_key_sgen_thread_info, value);
341 }
342
343 void mono_tls_set_lmf_addr (gpointer value)
344 {
345         MONO_TLS_SET_VALUE (mono_tls_lmf_addr, mono_tls_key_lmf_addr, value);
346 }