[mini] Always emit safepoints, except WASM
[mono-project.git] / mono / metadata / icall-table.c
blobdbbaca2e437432e46005ade951b01a0741ddba5e
1 /**
2 * \file
4 * Authors:
5 * Dietmar Maurer (dietmar@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
7 * Patrik Torstensson (patrik.torstensson@labs2.com)
8 * Marek Safar (marek.safar@gmail.com)
9 * Aleksey Kliger (aleksey@xamarin.com)
11 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
12 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
13 * Copyright 2011-2015 Xamarin Inc (http://www.xamarin.com).
14 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
17 #include <config.h>
18 #include <glib.h>
19 #include <stdarg.h>
20 #include <string.h>
21 #include <ctype.h>
22 #ifdef HAVE_ALLOCA_H
23 #include <alloca.h>
24 #endif
25 #ifdef HAVE_SYS_TIME_H
26 #include <sys/time.h>
27 #endif
28 #ifdef HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
31 #if defined (HAVE_WCHAR_H)
32 #include <wchar.h>
33 #endif
35 #include <mono/utils/mono-publib.h>
36 #include <mono/utils/bsearch.h>
37 #include <mono/metadata/icalls.h>
38 #include "handle-decl.h"
39 #include "icall-decl.h"
41 // These definitions are used for multiple includes of icall-def.h and eventually undefined.
42 #define NOHANDLES(inner) inner
43 #define HANDLES(id, name, func, ...) ICALL (id, name, func ## _raw)
44 #define HANDLES_REUSE_WRAPPER HANDLES
45 #define MONO_HANDLE_REGISTER_ICALL(...) /* nothing */
47 // Generate Icall_ constants
48 enum {
49 #define ICALL_TYPE(id,name,first) /* nothing */
50 #define ICALL_TYPE(id,name,first)
51 #define ICALL(id,name,func) Icall_ ## id,
52 #include "metadata/icall-def.h"
53 #undef ICALL_TYPE
54 #undef ICALL
55 Icall_last
58 enum {
59 #define ICALL_TYPE(id,name,first) Icall_type_ ## id,
60 #define ICALL(id,name,func) /* nothing */
61 #include "metadata/icall-def.h"
62 #undef ICALL_TYPE
63 #undef ICALL
64 Icall_type_num
67 typedef struct {
68 guint16 first_icall;
69 } IcallTypeDesc;
71 static const IcallTypeDesc icall_type_descs [] = {
72 #define ICALL_TYPE(id,name,firstic) {(Icall_ ## firstic)},
73 #define ICALL(id,name,func) /* nothing */
74 #include "metadata/icall-def.h"
75 #undef ICALL_TYPE
76 #undef ICALL
77 {Icall_last}
80 #define icall_desc_num_icalls(desc) ((desc) [1].first_icall - (desc) [0].first_icall)
82 // This, instead of an array of pointers, to optimize away a pointer and a relocation per string.
84 #define MSGSTRFIELD(line) MSGSTRFIELD1(line)
85 #define MSGSTRFIELD1(line) str##line
87 static const struct msgstrtn_t {
88 #define ICALL_TYPE(id,name,first) char MSGSTRFIELD(__LINE__) [sizeof (name)];
89 #define ICALL(id,name,func) /* nothing */
90 #include "metadata/icall-def.h"
91 #undef ICALL_TYPE
92 #undef ICALL
93 } icall_type_names_str = {
94 #define ICALL_TYPE(id,name,first) (name),
95 #define ICALL(id,name,func)
96 #include "metadata/icall-def.h"
97 #undef ICALL_TYPE
98 #undef ICALL
101 static const guint16 icall_type_names_idx [] = {
102 #define ICALL_TYPE(id,name,first) (offsetof (struct msgstrtn_t, MSGSTRFIELD(__LINE__))),
103 #define ICALL(id,name,func) /* nothing */
104 #include "metadata/icall-def.h"
105 #undef ICALL_TYPE
106 #undef ICALL
109 #define icall_type_name_get(id) ((const char*)&icall_type_names_str + icall_type_names_idx [(id)])
111 static const struct msgstr_t {
112 #define ICALL_TYPE(id,name,first) /* nothing */
113 #define ICALL(id,name,func) char MSGSTRFIELD(__LINE__) [sizeof (name)];
114 #include "metadata/icall-def.h"
115 #undef ICALL_TYPE
116 #undef ICALL
117 } icall_names_str = {
118 #define ICALL_TYPE(id,name,first)
119 #define ICALL(id,name,func) (name),
120 #include "metadata/icall-def.h"
121 #undef ICALL_TYPE
122 #undef ICALL
125 static const guint16 icall_names_idx [] = {
126 #define ICALL_TYPE(id,name,first) /* nothing */
127 #define ICALL(id,name,func) (offsetof (struct msgstr_t, MSGSTRFIELD(__LINE__))),
128 #include "metadata/icall-def.h"
129 #undef ICALL_TYPE
130 #undef ICALL
133 #define icall_name_get(id) ((const char*)&icall_names_str + icall_names_idx [(id)])
135 static const gconstpointer icall_functions [] = {
136 #define ICALL_TYPE(id,name,first) /* nothing */
137 #define ICALL(id,name,func) ((gpointer)(func)),
138 #include "metadata/icall-def.h"
139 #undef ICALL_TYPE
140 #undef ICALL
141 NULL
144 #ifdef ENABLE_ICALL_SYMBOL_MAP
146 static const gconstpointer icall_symbols [] = {
147 #define ICALL_TYPE(id,name,first) /* nothing */
148 #define ICALL(id,name,func) #func,
149 #include "metadata/icall-def.h"
150 #undef ICALL_TYPE
151 #undef ICALL
152 NULL
155 #endif // ENABLE_ICALL_SYMBOL_MAP
157 #undef HANDLES
158 #undef NOHANDLES
160 static const guchar icall_uses_handles [] = {
161 #define ICALL_TYPE(id,name,first) /* nothing */
162 #define ICALL(id,name,func) 0,
163 #define HANDLES(...) 1,
164 #define NOHANDLES(inner) 0,
165 #include "metadata/icall-def.h"
166 #undef ICALL_TYPE
167 #undef ICALL
170 #undef HANDLES
171 #undef HANDLES_REUSE_WRAPPER
172 #undef NOHANDLES
173 #undef MONO_HANDLE_REGISTER_ICALL
175 static int
176 compare_method_imap (const void *key, const void *elem)
178 const char* method_name = (const char*)&icall_names_str + (*(guint16*)elem);
179 return strcmp ((const char*)key, method_name);
182 static gsize
183 find_slot_icall (const IcallTypeDesc *imap, const char *name)
185 const guint16 *nameslot = (const guint16 *)mono_binary_search (name, icall_names_idx + imap->first_icall, icall_desc_num_icalls (imap), sizeof (icall_names_idx [0]), compare_method_imap);
186 if (!nameslot)
187 return -1;
188 return (nameslot - &icall_names_idx [0]);
191 static gboolean
192 find_uses_handles_icall (const IcallTypeDesc *imap, const char *name)
194 gsize slotnum = find_slot_icall (imap, name);
195 if (slotnum == -1)
196 return FALSE;
197 return (gboolean)icall_uses_handles [slotnum];
200 static gpointer
201 find_method_icall (const IcallTypeDesc *imap, const char *name)
203 gsize slotnum = find_slot_icall (imap, name);
204 if (slotnum == -1)
205 return NULL;
206 return (gpointer)icall_functions [slotnum];
209 static int
210 compare_class_imap (const void *key, const void *elem)
212 const char* class_name = (const char*)&icall_type_names_str + (*(guint16*)elem);
213 return strcmp ((const char*)key, class_name);
216 static const IcallTypeDesc*
217 find_class_icalls (const char *name)
219 const guint16 *nameslot = (const guint16 *)mono_binary_search (name, icall_type_names_idx, Icall_type_num, sizeof (icall_type_names_idx [0]), compare_class_imap);
220 if (!nameslot)
221 return NULL;
222 return &icall_type_descs [nameslot - &icall_type_names_idx [0]];
225 static gpointer
226 icall_table_lookup (char *classname, char *methodname, char *sigstart, gboolean *uses_handles)
228 const IcallTypeDesc *imap = NULL;
229 gpointer res;
231 imap = find_class_icalls (classname);
233 /* it wasn't found in the static call tables */
234 if (!imap) {
235 if (uses_handles)
236 *uses_handles = FALSE;
237 return NULL;
239 res = find_method_icall (imap, methodname);
240 if (res) {
241 if (uses_handles)
242 *uses_handles = find_uses_handles_icall (imap, methodname);
243 return res;
245 /* try _with_ signature */
246 *sigstart = '(';
247 res = find_method_icall (imap, methodname);
248 if (res) {
249 if (uses_handles)
250 *uses_handles = find_uses_handles_icall (imap, methodname);
251 return res;
253 return NULL;
256 #ifdef ENABLE_ICALL_SYMBOL_MAP
257 static int
258 func_cmp (gconstpointer key, gconstpointer p)
260 return (gsize)key - (gsize)*(gsize*)p;
262 #endif
264 static const char*
265 lookup_icall_symbol (gpointer func)
267 #ifdef ENABLE_ICALL_SYMBOL_MAP
268 int i;
269 gpointer slot;
270 static gconstpointer *functions_sorted;
271 static const char**symbols_sorted;
272 static gboolean inited;
274 if (!inited) {
275 gboolean changed;
277 functions_sorted = g_malloc (G_N_ELEMENTS (icall_functions) * sizeof (gpointer));
278 memcpy (functions_sorted, icall_functions, G_N_ELEMENTS (icall_functions) * sizeof (gpointer));
279 symbols_sorted = g_malloc (G_N_ELEMENTS (icall_functions) * sizeof (gpointer));
280 memcpy (symbols_sorted, icall_symbols, G_N_ELEMENTS (icall_functions) * sizeof (gpointer));
281 /* Bubble sort the two arrays */
282 changed = TRUE;
283 while (changed) {
284 changed = FALSE;
285 for (i = 0; i < G_N_ELEMENTS (icall_functions) - 1; ++i) {
286 if (functions_sorted [i] > functions_sorted [i + 1]) {
287 gconstpointer tmp;
289 tmp = functions_sorted [i];
290 functions_sorted [i] = functions_sorted [i + 1];
291 functions_sorted [i + 1] = tmp;
292 tmp = symbols_sorted [i];
293 symbols_sorted [i] = symbols_sorted [i + 1];
294 symbols_sorted [i + 1] = (const char*)tmp;
295 changed = TRUE;
299 inited = TRUE;
302 slot = mono_binary_search (func, functions_sorted, G_N_ELEMENTS (icall_functions), sizeof (gpointer), func_cmp);
303 if (!slot)
304 return NULL;
305 g_assert (slot);
306 return symbols_sorted [(gpointer*)slot - (gpointer*)functions_sorted];
307 #else
308 fprintf (stderr, "icall symbol maps not enabled, pass --enable-icall-symbol-map to configure.\n");
309 g_assert_not_reached ();
310 return NULL;
311 #endif
314 void
315 mono_icall_table_init (void)
317 int i = 0;
319 /* check that tables are sorted: disable in release */
320 if (TRUE) {
321 int j;
322 const char *prev_class = NULL;
323 const char *prev_method;
325 for (i = 0; i < Icall_type_num; ++i) {
326 const IcallTypeDesc *desc;
327 int num_icalls;
328 prev_method = NULL;
329 if (prev_class && strcmp (prev_class, icall_type_name_get (i)) >= 0)
330 g_print ("class %s should come before class %s\n", icall_type_name_get (i), prev_class);
331 prev_class = icall_type_name_get (i);
332 desc = &icall_type_descs [i];
333 num_icalls = icall_desc_num_icalls (desc);
334 /*g_print ("class %s has %d icalls starting at %d\n", prev_class, num_icalls, desc->first_icall);*/
335 for (j = 0; j < num_icalls; ++j) {
336 const char *methodn = icall_name_get (desc->first_icall + j);
337 if (prev_method && strcmp (prev_method, methodn) >= 0)
338 g_print ("method %s should come before method %s\n", methodn, prev_method);
339 prev_method = methodn;
344 MonoIcallTableCallbacks cb;
345 memset (&cb, 0, sizeof (MonoIcallTableCallbacks));
346 cb.version = MONO_ICALL_TABLE_CALLBACKS_VERSION;
347 cb.lookup = icall_table_lookup;
348 cb.lookup_icall_symbol = lookup_icall_symbol;
350 mono_install_icall_table_callbacks (&cb);