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.
25 #ifdef HAVE_SYS_TIME_H
31 #if defined (HAVE_WCHAR_H)
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 //#define TEST_ICALL_SYMBOL_MAP 1
49 // Generate Icall_ constants
51 #define ICALL_TYPE(id,name,first) /* nothing */
52 #define ICALL_TYPE(id,name,first)
53 #define ICALL(id,name,func) Icall_ ## id,
54 #include "metadata/icall-def.h"
61 #define ICALL_TYPE(id,name,first) Icall_type_ ## id,
62 #define ICALL(id,name,func) /* nothing */
63 #include "metadata/icall-def.h"
73 static const IcallTypeDesc icall_type_descs
[] = {
74 #define ICALL_TYPE(id,name,firstic) {(Icall_ ## firstic)},
75 #define ICALL(id,name,func) /* nothing */
76 #include "metadata/icall-def.h"
82 #define icall_desc_num_icalls(desc) ((desc) [1].first_icall - (desc) [0].first_icall)
84 // This, instead of an array of pointers, to optimize away a pointer and a relocation per string.
86 #define MSGSTRFIELD(line) MSGSTRFIELD1(line)
87 #define MSGSTRFIELD1(line) str##line
89 static const struct msgstrtn_t
{
90 #define ICALL_TYPE(id,name,first) char MSGSTRFIELD(__LINE__) [sizeof (name)];
91 #define ICALL(id,name,func) /* nothing */
92 #include "metadata/icall-def.h"
95 } icall_type_names_str
= {
96 #define ICALL_TYPE(id,name,first) (name),
97 #define ICALL(id,name,func)
98 #include "metadata/icall-def.h"
103 static const guint16 icall_type_names_idx
[] = {
104 #define ICALL_TYPE(id,name,first) (offsetof (struct msgstrtn_t, MSGSTRFIELD(__LINE__))),
105 #define ICALL(id,name,func) /* nothing */
106 #include "metadata/icall-def.h"
111 #define icall_type_name_get(id) ((const char*)&icall_type_names_str + icall_type_names_idx [(id)])
113 static const struct msgstr_t
{
114 #define ICALL_TYPE(id,name,first) /* nothing */
115 #define ICALL(id,name,func) char MSGSTRFIELD(__LINE__) [sizeof (name)];
116 #include "metadata/icall-def.h"
119 } icall_names_str
= {
120 #define ICALL_TYPE(id,name,first)
121 #define ICALL(id,name,func) (name),
122 #include "metadata/icall-def.h"
127 static const guint16 icall_names_idx
[] = {
128 #define ICALL_TYPE(id,name,first) /* nothing */
129 #define ICALL(id,name,func) (offsetof (struct msgstr_t, MSGSTRFIELD(__LINE__))),
130 #include "metadata/icall-def.h"
135 #define icall_name_get(id) ((const char*)&icall_names_str + icall_names_idx [(id)])
137 typedef struct MonoICallFunction
{
139 #if ENABLE_ICALL_SYMBOL_MAP || TEST_ICALL_SYMBOL_MAP
144 static const MonoICallFunction icall_functions
[] = {
145 #define ICALL_TYPE(id,name,first) /* nothing */
146 #if ENABLE_ICALL_SYMBOL_MAP || TEST_ICALL_SYMBOL_MAP
147 #define ICALL(id, name, func) { (gpointer)func, #func },
149 #define ICALL(id, name, func) { (gpointer)func },
151 #include "metadata/icall-def.h"
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"
171 #undef HANDLES_REUSE_WRAPPER
173 #undef MONO_HANDLE_REGISTER_ICALL
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
);
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
);
188 return (nameslot
- &icall_names_idx
[0]);
192 find_uses_handles_icall (const IcallTypeDesc
*imap
, const char *name
)
194 const gssize slotnum
= find_slot_icall (imap
, name
);
197 return (gboolean
)icall_uses_handles
[slotnum
];
201 find_method_icall (const IcallTypeDesc
*imap
, const char *name
)
203 const gssize slotnum
= find_slot_icall (imap
, name
);
206 return icall_functions
[slotnum
].func
;
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
);
222 return &icall_type_descs
[nameslot
- &icall_type_names_idx
[0]];
226 icall_table_lookup (MonoMethod
*method
, char *classname
, char *methodname
, char *sigstart
, gboolean
*uses_handles
)
228 const IcallTypeDesc
*imap
= NULL
;
231 imap
= find_class_icalls (classname
);
233 /* it wasn't found in the static call tables */
236 *uses_handles
= FALSE
;
239 res
= find_method_icall (imap
, methodname
);
242 *uses_handles
= find_uses_handles_icall (imap
, methodname
);
245 /* try _with_ signature */
247 res
= find_method_icall (imap
, methodname
);
250 *uses_handles
= find_uses_handles_icall (imap
, methodname
);
256 #if ENABLE_ICALL_SYMBOL_MAP || TEST_ICALL_SYMBOL_MAP
263 mono_qsort_icall_function_compare_indirect (gconstpointer va
, gconstpointer vb
)
265 const gpointer a
= icall_functions
[*(const guint16
*)va
].func
;
266 const gpointer b
= icall_functions
[*(const guint16
*)vb
].func
;
267 return (a
< b
) ? -1 : (a
> b
) ? 1 : 0;
275 mono_bsearch_icall_function_compare_indirect (gconstpointer a
, gconstpointer vb
)
277 const gpointer b
= icall_functions
[*(const guint16
*)vb
].func
;
278 return (a
< b
) ? -1 : (a
> b
) ? 1 : 0;
281 #endif // ENABLE_ICALL_SYMBOL_MAP || TEST_ICALL_SYMBOL_MAP
283 #if !TEST_ICALL_SYMBOL_MAP
287 mono_lookup_icall_symbol_internal (gpointer func
)
289 #if ENABLE_ICALL_SYMBOL_MAP || TEST_ICALL_SYMBOL_MAP
291 const gsize N
= G_N_ELEMENTS (icall_functions
) - 1; // skip terminal null element
292 g_static_assert (N
<= 0xFFFF); // If this fails, change T to guint32
293 static T
*static_functions_sorted
;
298 if (!static_functions_sorted
) {
300 T
*functions_sorted
= g_new (T
, N
);
302 // Initialize with identity mapping. One line is easier to step over.
303 for (T i
= 0; i
< N
; ++i
) functions_sorted
[i
] = i
;
305 mono_qsort (functions_sorted
, N
, sizeof (T
), mono_qsort_icall_function_compare_indirect
);
307 gpointer old
= mono_atomic_cas_ptr ((gpointer
*)&static_functions_sorted
, functions_sorted
, NULL
);
309 g_free (functions_sorted
);
312 T
const * const slot
= (const T
*)bsearch (func
, static_functions_sorted
, N
, sizeof (T
), mono_bsearch_icall_function_compare_indirect
);
315 return icall_functions
[*slot
].name
;
317 fprintf (stderr
, "icall symbol maps not enabled, pass --enable-icall-symbol-map to configure.\n");
318 g_assert_not_reached ();
324 mono_icall_table_init (void)
328 /* check that tables are sorted: disable in release */
331 const char *prev_class
= NULL
;
332 const char *prev_method
;
334 for (i
= 0; i
< Icall_type_num
; ++i
) {
335 const IcallTypeDesc
*desc
;
338 if (prev_class
&& strcmp (prev_class
, icall_type_name_get (i
)) >= 0)
339 g_print ("class %s should come before class %s\n", icall_type_name_get (i
), prev_class
);
340 prev_class
= icall_type_name_get (i
);
341 desc
= &icall_type_descs
[i
];
342 num_icalls
= icall_desc_num_icalls (desc
);
343 /*g_print ("class %s has %d icalls starting at %d\n", prev_class, num_icalls, desc->first_icall);*/
344 for (j
= 0; j
< num_icalls
; ++j
) {
345 const char *methodn
= icall_name_get (desc
->first_icall
+ j
);
346 if (prev_method
&& strcmp (prev_method
, methodn
) >= 0)
347 g_print ("method %s should come before method %s\n", methodn
, prev_method
);
348 prev_method
= methodn
;
353 static const MonoIcallTableCallbacks mono_icall_table_callbacks
=
355 MONO_ICALL_TABLE_CALLBACKS_VERSION
,
357 mono_lookup_icall_symbol_internal
,
359 mono_install_icall_table_callbacks (&mono_icall_table_callbacks
);