Allow runtime to be built with C++ on AIX (#17672)
[mono-project.git] / mono / utils / mono-tls.c
blob3c1ceed775959d89d0a41c2cf126314ec3bc605c
1 /**
2 * \file
3 * Low-level TLS support
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
8 * Copyright 2013 Xamarin, Inc (http://www.xamarin.com)
9 */
11 #include "mono-tls.h"
12 #include "mono-tls-inline.h"
14 #ifdef MONO_KEYWORD_THREAD
16 /* Runtime offset detection */
17 #if defined(TARGET_AMD64) && !defined(TARGET_MACH) && !defined(HOST_WIN32) /* __thread likely not tested on mac/win */
19 #if defined(PIC)
20 // This only works if libmono is linked into the application
21 #define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo; __asm ("movq " #var "@GOTTPOFF(%%rip), %0" : "=r" (foo)); offset = foo; } while (0)
22 #else
23 #define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo; __asm ("movq $" #var "@TPOFF, %0" : "=r" (foo)); offset = foo; } while (0)
24 #endif
26 #elif defined(TARGET_X86) && !defined(TARGET_MACH) && !defined(HOST_WIN32) && defined(__GNUC__)
28 #if defined(PIC)
29 #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)
30 #else
31 #define MONO_THREAD_VAR_OFFSET(var,offset) __asm ("movl $" #var "@ntpoff, %0" : "=r" (offset))
32 #endif
34 #elif defined(TARGET_ARM64) && !defined(PIC)
36 #define MONO_THREAD_VAR_OFFSET(var,offset) \
37 __asm ( "mov %0, #0\n add %0, %0, #:tprel_hi12:" #var "\n add %0, %0, #:tprel_lo12_nc:" #var "\n" \
38 : "=r" (offset))
40 #elif defined(TARGET_ARM) && defined(__ARM_EABI__) && !defined(PIC)
42 #define MONO_THREAD_VAR_OFFSET(var,offset) __asm (" ldr %0, 1f; b 2f; 1: .word " #var "(tpoff); 2:" : "=r" (offset))
44 #elif defined(TARGET_S390X)
45 # if defined(__PIC__)
46 # if !defined(__PIE__)
47 // This only works if libmono is linked into the application
48 # define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo; \
49 void *x = &var; \
50 __asm__ ("ear %%r1,%%a0\n" \
51 "sllg %%r1,%%r1,32\n" \
52 "ear %%r1,%%a1\n" \
53 "lgr %0,%1\n" \
54 "sgr %0,%%r1\n" \
55 : "=r" (foo) : "r" (x) \
56 : "1", "cc"); \
57 offset = foo; } while (0)
58 # elif __PIE__ == 1
59 # define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo; \
60 __asm__ ("lg %0," #var "@GOTNTPOFF(%%r12)\n\t" \
61 : "=r" (foo)); \
62 offset = foo; } while (0)
63 # elif __PIE__ == 2
64 # define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo; \
65 __asm__ ("larl %%r1," #var "@INDNTPOFF\n\t" \
66 "lg %0,0(%%r1)\n\t" \
67 : "=r" (foo) : \
68 : "1", "cc"); \
69 offset = foo; } while (0)
70 # endif
71 # else
72 # define MONO_THREAD_VAR_OFFSET(var,offset) do { guint64 foo; \
73 __asm__ ("basr %%r1,0\n\t" \
74 "j 0f\n\t" \
75 ".quad " #var "@NTPOFF\n" \
76 "0:\n\t" \
77 "lg %0,4(%%r1)\n\t" \
78 : "=r" (foo) : : "1"); \
79 offset = foo; } while (0)
80 # endif
82 #elif defined (TARGET_RISCV) && !defined (PIC)
84 #define MONO_THREAD_VAR_OFFSET(var, offset) \
85 do { \
86 guint32 temp; \
87 __asm__ ( \
88 "lui %0, %%tprel_hi(" #var ")\n" \
89 "add %0, %0, tp, %%tprel_add(" #var ")\n" \
90 "addi %0, %0, %%tprel_lo(" #var ")\n" \
91 : "=r" (temp) \
92 ); \
93 offset = temp; \
94 } while (0)
96 #else
98 #define MONO_THREAD_VAR_OFFSET(var,offset) (offset) = -1
100 #endif
102 // Tls variables for each MonoTlsKey.
103 // These are extern instead of static for inexplicable C++ compatibility.
105 MONO_KEYWORD_THREAD MonoInternalThread *mono_tls_thread MONO_TLS_FAST;
106 MONO_KEYWORD_THREAD MonoJitTlsData *mono_tls_jit_tls MONO_TLS_FAST;
107 MONO_KEYWORD_THREAD MonoDomain *mono_tls_domain MONO_TLS_FAST;
108 MONO_KEYWORD_THREAD SgenThreadInfo *mono_tls_sgen_thread_info MONO_TLS_FAST;
109 MONO_KEYWORD_THREAD MonoLMF **mono_tls_lmf_addr MONO_TLS_FAST;
111 #else
113 #if defined(TARGET_AMD64) && (defined(TARGET_MACH) || defined(HOST_WIN32))
114 #define MONO_THREAD_VAR_OFFSET(key,offset) (offset) = (gint32)key
115 #elif defined(TARGET_X86) && (defined(TARGET_MACH) || defined(HOST_WIN32))
116 #define MONO_THREAD_VAR_OFFSET(key,offset) (offset) = (gint32)key
117 #else
118 #define MONO_THREAD_VAR_OFFSET(var,offset) (offset) = -1
119 #endif
121 MonoNativeTlsKey mono_tls_key_thread;
122 MonoNativeTlsKey mono_tls_key_jit_tls;
123 MonoNativeTlsKey mono_tls_key_domain;
124 MonoNativeTlsKey mono_tls_key_sgen_thread_info;
125 MonoNativeTlsKey mono_tls_key_lmf_addr;
127 #endif
129 gint32 mono_tls_offsets [TLS_KEY_NUM];
131 void
132 mono_tls_init_gc_keys (void)
134 #ifdef MONO_KEYWORD_THREAD
135 MONO_THREAD_VAR_OFFSET (mono_tls_sgen_thread_info, mono_tls_offsets [TLS_KEY_SGEN_THREAD_INFO]);
136 #else
137 mono_native_tls_alloc (&mono_tls_key_sgen_thread_info, NULL);
138 MONO_THREAD_VAR_OFFSET (mono_tls_key_sgen_thread_info, mono_tls_offsets [TLS_KEY_SGEN_THREAD_INFO]);
139 #endif
142 void
143 mono_tls_init_runtime_keys (void)
145 #ifdef MONO_KEYWORD_THREAD
146 MONO_THREAD_VAR_OFFSET (mono_tls_thread, mono_tls_offsets [TLS_KEY_THREAD]);
147 MONO_THREAD_VAR_OFFSET (mono_tls_jit_tls, mono_tls_offsets [TLS_KEY_JIT_TLS]);
148 MONO_THREAD_VAR_OFFSET (mono_tls_domain, mono_tls_offsets [TLS_KEY_DOMAIN]);
149 MONO_THREAD_VAR_OFFSET (mono_tls_lmf_addr, mono_tls_offsets [TLS_KEY_LMF_ADDR]);
150 #else
151 mono_native_tls_alloc (&mono_tls_key_thread, NULL);
152 MONO_THREAD_VAR_OFFSET (mono_tls_key_thread, mono_tls_offsets [TLS_KEY_THREAD]);
153 mono_native_tls_alloc (&mono_tls_key_jit_tls, NULL);
154 MONO_THREAD_VAR_OFFSET (mono_tls_key_jit_tls, mono_tls_offsets [TLS_KEY_JIT_TLS]);
155 mono_native_tls_alloc (&mono_tls_key_domain, NULL);
156 MONO_THREAD_VAR_OFFSET (mono_tls_key_domain, mono_tls_offsets [TLS_KEY_DOMAIN]);
157 mono_native_tls_alloc (&mono_tls_key_lmf_addr, NULL);
158 MONO_THREAD_VAR_OFFSET (mono_tls_key_lmf_addr, mono_tls_offsets [TLS_KEY_LMF_ADDR]);
159 #endif
162 void
163 mono_tls_free_keys (void)
165 #ifndef MONO_KEYWORD_THREAD
166 mono_native_tls_free (mono_tls_key_thread);
167 mono_native_tls_free (mono_tls_key_jit_tls);
168 mono_native_tls_free (mono_tls_key_domain);
169 mono_native_tls_free (mono_tls_key_sgen_thread_info);
170 mono_native_tls_free (mono_tls_key_lmf_addr);
171 #endif
174 // Some references are from AOT and cannot be inlined.
176 G_EXTERN_C MonoInternalThread *mono_tls_get_thread_extern (void)
178 return mono_tls_get_thread ();
181 G_EXTERN_C MonoJitTlsData *mono_tls_get_jit_tls_extern (void)
183 return mono_tls_get_jit_tls ();
186 G_EXTERN_C MonoDomain *mono_tls_get_domain_extern (void)
188 return mono_tls_get_domain ();
191 G_EXTERN_C SgenThreadInfo *mono_tls_get_sgen_thread_info_extern (void)
193 return mono_tls_get_sgen_thread_info ();
196 G_EXTERN_C MonoLMF **mono_tls_get_lmf_addr_extern (void)
198 return mono_tls_get_lmf_addr ();