1 /**
2 * \file
3 * Routines for marshaling complex types in P/Invoke methods.
4 *
5 * Author:
6 * Paolo Molaro (lupus@ximian.com)
7 *
8 * Copyright 2002-2003 Ximian, Inc (http://www.ximian.com)
9 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
10 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11 *
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
13 */
14
15 #include "config.h"
16 #ifdef HAVE_ALLOCA_H
17 #include <alloca.h>
18 #endif
19
20 #include "object.h"
21 #include "loader.h"
22 #include "cil-coff.h"
23 #include "metadata/marshal.h"
24 #include "metadata/marshal-internals.h"
25 #include "metadata/method-builder.h"
26 #include "metadata/tabledefs.h"
27 #include "metadata/exception.h"
28 #include "metadata/appdomain.h"
29 #include "mono/metadata/abi-details.h"
30 #include "mono/metadata/debug-helpers.h"
31 #include "mono/metadata/threads.h"
32 #include "mono/metadata/monitor.h"
33 #include "mono/metadata/class-internals.h"
34 #include "mono/metadata/metadata-internals.h"
35 #include "mono/metadata/domain-internals.h"
36 #include "mono/metadata/gc-internals.h"
37 #include "mono/metadata/threads-types.h"
38 #include "mono/metadata/string-icalls.h"
39 #include "mono/metadata/attrdefs.h"
40 #include "mono/metadata/cominterop.h"
41 #include "mono/metadata/remoting.h"
42 #include "mono/metadata/reflection-internals.h"
43 #include "mono/metadata/threadpool.h"
44 #include "mono/metadata/handle.h"
45 #include "mono/utils/mono-counters.h"
46 #include "mono/utils/mono-tls.h"
47 #include "mono/utils/mono-memory-model.h"
48 #include "mono/utils/atomic.h"
49 #include <mono/utils/mono-threads.h>
50 #include <mono/utils/mono-threads-coop.h>
51 #include <mono/utils/mono-error-internals.h>
52
53 #include <string.h>
54 #include <errno.h>
55
56 /* #define DEBUG_RUNTIME_CODE */
57
58 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
59 a = i,
60
61 enum {
62 #include "mono/cil/opcode.def"
63 LAST = 0xff
64 };
65 #undef OPDEF
66
67 /*
68 * This mutex protects the various marshalling related caches in MonoImage
69 * and a few other data structures static to this file.
70 *
71 * The marshal lock is a non-recursive complex lock that sits below the domain lock in the
72 * runtime locking latice. Which means it can take simple locks suck as the image lock.
73 */
74 #define mono_marshal_lock() mono_locks_os_acquire (&marshal_mutex, MarshalLock)
75 #define mono_marshal_unlock() mono_locks_os_release (&marshal_mutex, MarshalLock)
76 static mono_mutex_t marshal_mutex;
77 static gboolean marshal_mutex_initialized;
78
79 static MonoNativeTlsKey last_error_tls_id;
80
81 static MonoNativeTlsKey load_type_info_tls_id;
82
83 static gboolean use_aot_wrappers;
84
85 static int class_marshal_info_count;
86
87 static void ftnptr_eh_callback_default (guint32 gchandle);
88
89 static MonoFtnPtrEHCallback ftnptr_eh_callback = ftnptr_eh_callback_default;
90
91 static void
92 delegate_hash_table_add (MonoDelegateHandle d);
93
94 static void
95 delegate_hash_table_remove (MonoDelegate *d);
96
97 static void
98 emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object);
99
100 static void
101 emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object, int offset_of_first_child_field, MonoMarshalNative string_encoding);
102
103 static void
104 mono_struct_delete_old (MonoClass *klass, char *ptr);
105
106 MONO_API void *
107 mono_marshal_string_to_utf16 (MonoString *s);
108
109 static void *
110 mono_marshal_string_to_utf16_copy (MonoString *s);
111
112 #ifndef HOST_WIN32
113 static gpointer
114 mono_string_to_utf8str (MonoString *string_obj);
115 #endif
116
117 static MonoStringBuilder *
118 mono_string_utf8_to_builder2 (char *text);
119
120 static MonoStringBuilder *
121 mono_string_utf16_to_builder2 (gunichar2 *text);
122
123 static MonoString*
124 mono_string_new_len_wrapper (const char *text, guint length);
125
126 static MonoString *
127 mono_string_from_byvalstr (const char *data, int len);
128
129 static MonoString *
130 mono_string_from_byvalwstr (gunichar2 *data, int len);
131
132 static void
133 mono_byvalarray_to_array (MonoArray *arr, gpointer native_arr, MonoClass *eltype, guint32 elnum);
134
135 static void
136 mono_byvalarray_to_byte_array (MonoArray *arr, gpointer native_arr, guint32 elnum);
137
138 static void
139 mono_array_to_byvalarray (gpointer native_arr, MonoArray *arr, MonoClass *eltype, guint32 elnum);
140
141 static void
142 mono_array_to_byte_byvalarray (gpointer native_arr, MonoArray *arr, guint32 elnum);
143
144 static MonoAsyncResult *
145 mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params);
146
147 static MonoObject *
148 mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params);
149
150 static void
151 mono_marshal_set_last_error_windows (int error);
152
153 static MonoObject *
154 mono_marshal_isinst_with_cache (MonoObject *obj, MonoClass *klass, uintptr_t *cache);
155
156 static void init_safe_handle (void);
157
158 static void*
159 ves_icall_marshal_alloc (gsize size);
160
161 void
162 mono_string_utf8_to_builder (MonoStringBuilder *sb, char *text);
163
164 void
165 mono_string_utf16_to_builder (MonoStringBuilder *sb, gunichar2 *text);
166
167 gchar*
168 mono_string_builder_to_utf8 (MonoStringBuilder *sb);
169
170 gunichar2*
171 mono_string_builder_to_utf16 (MonoStringBuilder *sb);
172
173 void
174 mono_string_to_byvalstr (gpointer dst, MonoString *src, int size);
175
176 void
177 mono_string_to_byvalwstr (gpointer dst, MonoString *src, int size);
178
179 gpointer
180 mono_delegate_to_ftnptr (MonoDelegate *delegate);
181
182 gpointer
183 mono_delegate_handle_to_ftnptr (MonoDelegateHandle delegate, MonoError *error);
184
185 MonoDelegate*
186 mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn);
187
188 MonoDelegateHandle
189 mono_ftnptr_to_delegate_handle (MonoClass *klass, gpointer ftn, MonoError *error);
190
191 gpointer
192 mono_array_to_savearray (MonoArray *array);
193
194 gpointer
195 mono_array_to_lparray (MonoArray *array);
196
197 void
198 mono_free_lparray (MonoArray *array, gpointer* nativeArray);
199
200 gpointer
201 mono_marshal_asany (MonoObject *obj, MonoMarshalNative string_encoding, int param_attrs);
202
203 void
204 mono_marshal_free_asany (MonoObject *o, gpointer ptr, MonoMarshalNative string_encoding, int param_attrs);
205
206 gpointer
207 mono_array_to_savearray (MonoArray *array);
208
209 gpointer
210 mono_array_to_lparray (MonoArray *array);
211
212 void
213 mono_free_lparray (MonoArray *array, gpointer* nativeArray);
214
215 static void
216 mono_marshal_ftnptr_eh_callback (guint32 gchandle);
217
218 static MonoThreadInfo*
219 mono_icall_start (HandleStackMark *stackmark, MonoError *error);
220
221 static void
222 mono_icall_end (MonoThreadInfo *info, HandleStackMark *stackmark, MonoError *error);
223
224 static MonoObjectHandle
225 mono_icall_handle_new (gpointer rawobj);
226
227 static MonoObjectHandle
228 mono_icall_handle_new_interior (gpointer rawobj);
229
230 /* Lazy class loading functions */
231 static GENERATE_GET_CLASS_WITH_CACHE (string_builder, "System.Text", "StringBuilder");
232 static GENERATE_GET_CLASS_WITH_CACHE (date_time, "System", "DateTime");
233 static GENERATE_GET_CLASS_WITH_CACHE (fixed_buffer_attribute, "System.Runtime.CompilerServices", "FixedBufferAttribute");
234 static GENERATE_TRY_GET_CLASS_WITH_CACHE (unmanaged_function_pointer_attribute, "System.Runtime.InteropServices", "UnmanagedFunctionPointerAttribute");
235 static GENERATE_TRY_GET_CLASS_WITH_CACHE (icustom_marshaler, "System.Runtime.InteropServices", "ICustomMarshaler");
236
237 /* MonoMethod pointers to SafeHandle::DangerousAddRef and ::DangerousRelease */
238 static MonoMethod *sh_dangerous_add_ref;
239 static MonoMethod *sh_dangerous_release;
240
241 static void
init_safe_handle()242 init_safe_handle ()
243 {
244 sh_dangerous_add_ref = mono_class_get_method_from_name (
245 mono_class_try_get_safehandle_class (), "DangerousAddRef", 1);
246 sh_dangerous_release = mono_class_get_method_from_name (
247 mono_class_try_get_safehandle_class (), "DangerousRelease", 0);
248 }
249
250 static void
register_icall(gpointer func,const char * name,const char * sigstr,gboolean no_wrapper)251 register_icall (gpointer func, const char *name, const char *sigstr, gboolean no_wrapper)
252 {
253 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
254
255 mono_register_jit_icall (func, name, sig, no_wrapper);
256 }
257
258 static void
register_icall_no_wrapper(gpointer func,const char * name,const char * sigstr)259 register_icall_no_wrapper (gpointer func, const char *name, const char *sigstr)
260 {
261 MonoMethodSignature *sig = mono_create_icall_signature (sigstr);
262
263 mono_register_jit_icall (func, name, sig, TRUE);
264 }
265
266 MonoMethodSignature*
mono_signature_no_pinvoke(MonoMethod * method)267 mono_signature_no_pinvoke (MonoMethod *method)
268 {
269 MonoMethodSignature *sig = mono_method_signature (method);
270 if (sig->pinvoke) {
271 sig = mono_metadata_signature_dup_full (method->klass->image, sig);
272 sig->pinvoke = FALSE;
273 }
274
275 return sig;
276 }
277
278 void
mono_marshal_init_tls(void)279 mono_marshal_init_tls (void)
280 {
281 mono_native_tls_alloc (&last_error_tls_id, NULL);
282 mono_native_tls_alloc (&load_type_info_tls_id, NULL);
283 }
284
285 static MonoObject*
mono_object_isinst_icall(MonoObject * obj,MonoClass * klass)286 mono_object_isinst_icall (MonoObject *obj, MonoClass *klass)
287 {
288 if (!klass)
289 return NULL;
290
291 /* This is called from stelemref so it is expected to succeed */
292 /* Fastpath */
293 if (mono_class_is_interface (klass)) {
294 MonoVTable *vt = obj->vtable;
295
296 if (!klass->inited)
297 mono_class_init (klass);
298
299 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id))
300 return obj;
301 }
302
303 MonoError error;
304 MonoObject *result = mono_object_isinst_checked (obj, klass, &error);
305 mono_error_set_pending_exception (&error);
306 return result;
307 }
308
309 static MonoString*
ves_icall_mono_string_from_utf16(gunichar2 * data)310 ves_icall_mono_string_from_utf16 (gunichar2 *data)
311 {
312 MonoError error;
313 MonoString *result = mono_string_from_utf16_checked (data, &error);
314 mono_error_set_pending_exception (&error);
315 return result;
316 }
317
318 static char*
ves_icall_mono_string_to_utf8(MonoString * str)319 ves_icall_mono_string_to_utf8 (MonoString *str)
320 {
321 MonoError error;
322 char *result = mono_string_to_utf8_checked (str, &error);
323 mono_error_set_pending_exception (&error);
324 return result;
325 }
326
327 static MonoString*
ves_icall_string_new_wrapper(const char * text)328 ves_icall_string_new_wrapper (const char *text)
329 {
330 if (text) {
331 MonoError error;
332 MonoString *res = mono_string_new_checked (mono_domain_get (), text, &error);
333 mono_error_set_pending_exception (&error);
334 return res;
335 }
336
337 return NULL;
338 }
339
340 void
mono_marshal_init(void)341 mono_marshal_init (void)
342 {
343 static gboolean module_initialized = FALSE;
344
345 if (!module_initialized) {
346 module_initialized = TRUE;
347 mono_os_mutex_init_recursive (&marshal_mutex);
348 marshal_mutex_initialized = TRUE;
349
350 register_icall (ves_icall_System_Threading_Thread_ResetAbort, "ves_icall_System_Threading_Thread_ResetAbort", "void", TRUE);
351 register_icall (mono_marshal_string_to_utf16, "mono_marshal_string_to_utf16", "ptr obj", FALSE);
352 register_icall (mono_marshal_string_to_utf16_copy, "mono_marshal_string_to_utf16_copy", "ptr obj", FALSE);
353 register_icall (mono_string_to_utf16, "mono_string_to_utf16", "ptr obj", FALSE);
354 register_icall (ves_icall_mono_string_from_utf16, "ves_icall_mono_string_from_utf16", "obj ptr", FALSE);
355 register_icall (mono_string_from_byvalstr, "mono_string_from_byvalstr", "obj ptr int", FALSE);
356 register_icall (mono_string_from_byvalwstr, "mono_string_from_byvalwstr", "obj ptr int", FALSE);
357 register_icall (mono_string_new_wrapper, "mono_string_new_wrapper", "obj ptr", FALSE);
358 register_icall (ves_icall_string_new_wrapper, "ves_icall_string_new_wrapper", "obj ptr", FALSE);
359 register_icall (mono_string_new_len_wrapper, "mono_string_new_len_wrapper", "obj ptr int", FALSE);
360 register_icall (ves_icall_mono_string_to_utf8, "ves_icall_mono_string_to_utf8", "ptr obj", FALSE);
361 register_icall (mono_string_to_utf8str, "mono_string_to_utf8str", "ptr obj", FALSE);
362 register_icall (mono_string_to_ansibstr, "mono_string_to_ansibstr", "ptr object", FALSE);
363 register_icall (mono_string_builder_to_utf8, "mono_string_builder_to_utf8", "ptr object", FALSE);
364 register_icall (mono_string_builder_to_utf16, "mono_string_builder_to_utf16", "ptr object", FALSE);
365 register_icall (mono_array_to_savearray, "mono_array_to_savearray", "ptr object", FALSE);
366 register_icall (mono_array_to_lparray, "mono_array_to_lparray", "ptr object", FALSE);
367 register_icall (mono_free_lparray, "mono_free_lparray", "void object ptr", FALSE);
368 register_icall (mono_byvalarray_to_array, "mono_byvalarray_to_array", "void object ptr ptr int32", FALSE);
369 register_icall (mono_byvalarray_to_byte_array, "mono_byvalarray_to_byte_array", "void object ptr int32", FALSE);
370 register_icall (mono_array_to_byvalarray, "mono_array_to_byvalarray", "void ptr object ptr int32", FALSE);
371 register_icall (mono_array_to_byte_byvalarray, "mono_array_to_byte_byvalarray", "void ptr object int32", FALSE);
372 register_icall (mono_delegate_to_ftnptr, "mono_delegate_to_ftnptr", "ptr object", FALSE);
373 register_icall (mono_ftnptr_to_delegate, "mono_ftnptr_to_delegate", "object ptr ptr", FALSE);
374 register_icall (mono_marshal_asany, "mono_marshal_asany", "ptr object int32 int32", FALSE);
375 register_icall (mono_marshal_free_asany, "mono_marshal_free_asany", "void object ptr int32 int32", FALSE);
376 register_icall (ves_icall_marshal_alloc, "ves_icall_marshal_alloc", "ptr ptr", FALSE);
377 register_icall (mono_marshal_free, "mono_marshal_free", "void ptr", FALSE);
378 register_icall (mono_marshal_set_last_error, "mono_marshal_set_last_error", "void", TRUE);
379 register_icall (mono_marshal_set_last_error_windows, "mono_marshal_set_last_error_windows", "void int32", TRUE);
380 register_icall (mono_string_utf8_to_builder, "mono_string_utf8_to_builder", "void ptr ptr", FALSE);
381 register_icall (mono_string_utf8_to_builder2, "mono_string_utf8_to_builder2", "object ptr", FALSE);
382 register_icall (mono_string_utf16_to_builder, "mono_string_utf16_to_builder", "void ptr ptr", FALSE);
383 register_icall (mono_string_utf16_to_builder2, "mono_string_utf16_to_builder2", "object ptr", FALSE);
384 register_icall (mono_marshal_free_array, "mono_marshal_free_array", "void ptr int32", FALSE);
385 register_icall (mono_string_to_byvalstr, "mono_string_to_byvalstr", "void ptr ptr int32", FALSE);
386 register_icall (mono_string_to_byvalwstr, "mono_string_to_byvalwstr", "void ptr ptr int32", FALSE);
387 register_icall (g_free, "g_free", "void ptr", FALSE);
388 register_icall_no_wrapper (mono_object_isinst_icall, "mono_object_isinst_icall", "object object ptr");
389 register_icall (mono_struct_delete_old, "mono_struct_delete_old", "void ptr ptr", FALSE);
390 register_icall (mono_delegate_begin_invoke, "mono_delegate_begin_invoke", "object object ptr", FALSE);
391 register_icall (mono_delegate_end_invoke, "mono_delegate_end_invoke", "object object ptr", FALSE);
392 register_icall (mono_gc_wbarrier_generic_nostore, "wb_generic", "void ptr", FALSE);
393 register_icall (mono_gchandle_get_target, "mono_gchandle_get_target", "object int32", TRUE);
394 register_icall (mono_gchandle_new, "mono_gchandle_new", "uint32 object bool", TRUE);
395 register_icall (mono_marshal_isinst_with_cache, "mono_marshal_isinst_with_cache", "object object ptr ptr", FALSE);
396 register_icall (mono_marshal_ftnptr_eh_callback, "mono_marshal_ftnptr_eh_callback", "void uint32", TRUE);
397 register_icall (mono_threads_enter_gc_safe_region_unbalanced, "mono_threads_enter_gc_safe_region_unbalanced", "ptr ptr", TRUE);
398 register_icall (mono_threads_exit_gc_safe_region_unbalanced, "mono_threads_exit_gc_safe_region_unbalanced", "void ptr ptr", TRUE);
399 register_icall (mono_threads_attach_coop, "mono_threads_attach_coop", "ptr ptr ptr", TRUE);
400 register_icall (mono_threads_detach_coop, "mono_threads_detach_coop", "void ptr ptr", TRUE);
401 register_icall (mono_icall_start, "mono_icall_start", "ptr ptr ptr", TRUE);
402 register_icall (mono_icall_end, "mono_icall_end", "void ptr ptr ptr", TRUE);
403 register_icall (mono_icall_handle_new, "mono_icall_handle_new", "ptr ptr", TRUE);
404 register_icall (mono_icall_handle_new_interior, "mono_icall_handle_new_interior", "ptr ptr", TRUE);
405
406 mono_cominterop_init ();
407 mono_remoting_init ();
408
409 mono_counters_register ("MonoClass::class_marshal_info_count count",
410 MONO_COUNTER_METADATA | MONO_COUNTER_INT, &class_marshal_info_count);
411
412 }
413 }
414
415 void
mono_marshal_cleanup(void)416 mono_marshal_cleanup (void)
417 {
418 mono_cominterop_cleanup ();
419
420 mono_native_tls_free (load_type_info_tls_id);
421 mono_native_tls_free (last_error_tls_id);
422 mono_os_mutex_destroy (&marshal_mutex);
423 marshal_mutex_initialized = FALSE;
424 }
425
426 void
mono_marshal_lock_internal(void)427 mono_marshal_lock_internal (void)
428 {
429 mono_marshal_lock ();
430 }
431
432 void
mono_marshal_unlock_internal(void)433 mono_marshal_unlock_internal (void)
434 {
435 mono_marshal_unlock ();
436 }
437
438 /* This is a JIT icall, it sets the pending exception and return NULL on error */
439 gpointer
mono_delegate_to_ftnptr(MonoDelegate * delegate_raw)440 mono_delegate_to_ftnptr (MonoDelegate *delegate_raw)
441 {
442 HANDLE_FUNCTION_ENTER ();
443 MonoError error;
444 MONO_HANDLE_DCL (MonoDelegate, delegate);
445 gpointer result = mono_delegate_handle_to_ftnptr (delegate, &error);
446 mono_error_set_pending_exception (&error);
447 HANDLE_FUNCTION_RETURN_VAL (result);
448 }
449
450 gpointer
mono_delegate_handle_to_ftnptr(MonoDelegateHandle delegate,MonoError * error)451 mono_delegate_handle_to_ftnptr (MonoDelegateHandle delegate, MonoError *error)
452 {
453 HANDLE_FUNCTION_ENTER ();
454 gpointer result = NULL;
455 error_init (error);
456 MonoMethod *method, *wrapper;
457 MonoClass *klass;
458 uint32_t target_handle = 0;
459
460 if (MONO_HANDLE_IS_NULL (delegate))
461 goto leave;
462
463 if (MONO_HANDLE_GETVAL (delegate, delegate_trampoline)) {
464 result = MONO_HANDLE_GETVAL (delegate, delegate_trampoline);
465 goto leave;
466 }
467
468 klass = mono_handle_class (delegate);
469 g_assert (klass->delegate);
470
471 method = MONO_HANDLE_GETVAL (delegate, method);
472 if (MONO_HANDLE_GETVAL (delegate, method_is_virtual)) {
473 MonoObjectHandle delegate_target = MONO_HANDLE_NEW_GET (MonoObject, delegate, target);
474 method = mono_object_handle_get_virtual_method (delegate_target, method, error);
475 goto_if_nok (error, leave);
476 }
477
478 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
479 const char *exc_class, *exc_arg;
480 gpointer ftnptr;
481
482 ftnptr = mono_lookup_pinvoke_call (method, &exc_class, &exc_arg);
483 if (!ftnptr) {
484 g_assert (exc_class);
485 mono_error_set_generic_error (error, "System", exc_class, "%s", exc_arg);
486 goto leave;
487 }
488 result = ftnptr;
489 goto leave;
490 }
491
492 MonoObjectHandle delegate_target = MONO_HANDLE_NEW_GET (MonoObject, delegate, target);
493 if (!MONO_HANDLE_IS_NULL (delegate_target)) {
494 /* Produce a location which can be embedded in JITted code */
495 target_handle = mono_gchandle_new_weakref (MONO_HANDLE_RAW (delegate_target), FALSE); /* FIXME: a version of mono_gchandle_new_weakref that takes a coop handle */
496 }
497
498 wrapper = mono_marshal_get_managed_wrapper (method, klass, target_handle, error);
499 goto_if_nok (error, leave);
500
501 MONO_HANDLE_SETVAL (delegate, delegate_trampoline, gpointer, mono_compile_method_checked (wrapper, error));
502 goto_if_nok (error, leave);
503
504 // Add the delegate to the delegate hash table
505 delegate_hash_table_add (delegate);
506
507 /* when the object is collected, collect the dynamic method, too */
508 mono_object_register_finalizer ((MonoObject*) MONO_HANDLE_RAW (delegate));
509
510 result = MONO_HANDLE_GETVAL (delegate, delegate_trampoline);
511
512 leave:
513 if (!is_ok (error) && target_handle != 0)
514 mono_gchandle_free (target_handle);
515 HANDLE_FUNCTION_RETURN_VAL (result);
516 }
517
518 /*
519 * this hash table maps from a delegate trampoline object to a weak reference
520 * of the delegate. As an optimizations with a non-moving GC we store the
521 * object pointer itself, otherwise we use a GC handle.
522 */
523 static GHashTable *delegate_hash_table;
524
525 static GHashTable *
delegate_hash_table_new(void)526 delegate_hash_table_new (void) {
527 return g_hash_table_new (NULL, NULL);
528 }
529
530 static void
delegate_hash_table_remove(MonoDelegate * d)531 delegate_hash_table_remove (MonoDelegate *d)
532 {
533 guint32 gchandle = 0;
534
535 mono_marshal_lock ();
536 if (delegate_hash_table == NULL)
537 delegate_hash_table = delegate_hash_table_new ();
538 if (mono_gc_is_moving ())
539 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table, d->delegate_trampoline));
540 g_hash_table_remove (delegate_hash_table, d->delegate_trampoline);
541 mono_marshal_unlock ();
542 if (gchandle && mono_gc_is_moving ())
543 mono_gchandle_free (gchandle);
544 }
545
546 static void
delegate_hash_table_add(MonoDelegateHandle d)547 delegate_hash_table_add (MonoDelegateHandle d)
548 {
549 guint32 gchandle;
550 guint32 old_gchandle;
551
552 mono_marshal_lock ();
553 if (delegate_hash_table == NULL)
554 delegate_hash_table = delegate_hash_table_new ();
555 gpointer delegate_trampoline = MONO_HANDLE_GETVAL (d, delegate_trampoline);
556 if (mono_gc_is_moving ()) {
557 gchandle = mono_gchandle_new_weakref ((MonoObject*) MONO_HANDLE_RAW (d), FALSE);
558 old_gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table, delegate_trampoline));
559 g_hash_table_insert (delegate_hash_table, delegate_trampoline, GUINT_TO_POINTER (gchandle));
560 if (old_gchandle)
561 mono_gchandle_free (old_gchandle);
562 } else {
563 g_hash_table_insert (delegate_hash_table, delegate_trampoline, MONO_HANDLE_RAW (d));
564 }
565 mono_marshal_unlock ();
566 }
567
568 /*
569 * mono_marshal_use_aot_wrappers:
570 *
571 * Instructs this module to use AOT compatible wrappers.
572 */
573 void
mono_marshal_use_aot_wrappers(gboolean use)574 mono_marshal_use_aot_wrappers (gboolean use)
575 {
576 use_aot_wrappers = use;
577 }
578
579 static void
parse_unmanaged_function_pointer_attr(MonoClass * klass,MonoMethodPInvoke * piinfo)580 parse_unmanaged_function_pointer_attr (MonoClass *klass, MonoMethodPInvoke *piinfo)
581 {
582 MonoError error;
583 MonoCustomAttrInfo *cinfo;
584 MonoReflectionUnmanagedFunctionPointerAttribute *attr;
585
586 /* The attribute is only available in Net 2.0 */
587 if (mono_class_try_get_unmanaged_function_pointer_attribute_class ()) {
588 /*
589 * The pinvoke attributes are stored in a real custom attribute so we have to
590 * construct it.
591 */
592 cinfo = mono_custom_attrs_from_class_checked (klass, &error);
593 if (!mono_error_ok (&error)) {
594 g_warning ("Could not load UnmanagedFunctionPointerAttribute due to %s", mono_error_get_message (&error));
595 mono_error_cleanup (&error);
596 }
597 if (cinfo && !mono_runtime_get_no_exec ()) {
598 attr = (MonoReflectionUnmanagedFunctionPointerAttribute*)mono_custom_attrs_get_attr_checked (cinfo, mono_class_try_get_unmanaged_function_pointer_attribute_class (), &error);
599 if (attr) {
600 piinfo->piflags = (attr->call_conv << 8) | (attr->charset ? (attr->charset - 1) * 2 : 1) | attr->set_last_error;
601 } else {
602 if (!mono_error_ok (&error)) {
603 g_warning ("Could not load UnmanagedFunctionPointerAttribute due to %s", mono_error_get_message (&error));
604 mono_error_cleanup (&error);
605 }
606 }
607 if (!cinfo->cached)
608 mono_custom_attrs_free (cinfo);
609 }
610 }
611 }
612
613 /* This is a JIT icall, it sets the pending exception and returns NULL on error */
614 MonoDelegate*
mono_ftnptr_to_delegate(MonoClass * klass,gpointer ftn)615 mono_ftnptr_to_delegate (MonoClass *klass, gpointer ftn)
616 {
617 HANDLE_FUNCTION_ENTER ();
618 MonoError error;
619 MonoDelegateHandle result = mono_ftnptr_to_delegate_handle (klass, ftn, &error);
620 mono_error_set_pending_exception (&error);
621 HANDLE_FUNCTION_RETURN_OBJ (result);
622 }
623
624 MonoDelegateHandle
mono_ftnptr_to_delegate_handle(MonoClass * klass,gpointer ftn,MonoError * error)625 mono_ftnptr_to_delegate_handle (MonoClass *klass, gpointer ftn, MonoError *error)
626 {
627 HANDLE_FUNCTION_ENTER ();
628 error_init (error);
629 guint32 gchandle;
630 MonoDelegateHandle d = MONO_HANDLE_NEW (MonoDelegate, NULL);
631
632 if (ftn == NULL)
633 goto leave;
634
635 mono_marshal_lock ();
636 if (delegate_hash_table == NULL)
637 delegate_hash_table = delegate_hash_table_new ();
638
639 if (mono_gc_is_moving ()) {
640 gchandle = GPOINTER_TO_UINT (g_hash_table_lookup (delegate_hash_table, ftn));
641 mono_marshal_unlock ();
642 if (gchandle)
643 MONO_HANDLE_ASSIGN (d, MONO_HANDLE_CAST (MonoDelegate, mono_gchandle_get_target_handle (gchandle)));
644 } else {
645 MONO_HANDLE_ASSIGN (d, MONO_HANDLE_NEW (MonoDelegate, g_hash_table_lookup (delegate_hash_table, ftn)));
646 mono_marshal_unlock ();
647 }
648 if (MONO_HANDLE_IS_NULL (d)) {
649 /* This is a native function, so construct a delegate for it */
650 MonoMethodSignature *sig;
651 MonoMethod *wrapper;
652 MonoMarshalSpec **mspecs;
653 MonoMethod *invoke = mono_get_delegate_invoke (klass);
654 MonoMethodPInvoke piinfo;
655 MonoObjectHandle this_obj;
656 int i;
657
658 if (use_aot_wrappers) {
659 wrapper = mono_marshal_get_native_func_wrapper_aot (klass);
660 this_obj = MONO_HANDLE_NEW (MonoObject, mono_value_box_checked (mono_domain_get (), mono_defaults.int_class, &ftn, error));
661 goto_if_nok (error, leave);
662 } else {
663 memset (&piinfo, 0, sizeof (piinfo));
664 parse_unmanaged_function_pointer_attr (klass, &piinfo);
665
666 mspecs = g_new0 (MonoMarshalSpec*, mono_method_signature (invoke)->param_count + 1);
667 mono_method_get_marshal_info (invoke, mspecs);
668 /* Freed below so don't alloc from mempool */
669 sig = mono_metadata_signature_dup (mono_method_signature (invoke));
670 sig->hasthis = 0;
671
672 wrapper = mono_marshal_get_native_func_wrapper (klass->image, sig, &piinfo, mspecs, ftn);
673 this_obj = MONO_HANDLE_NEW (MonoObject, NULL);
674
675 for (i = mono_method_signature (invoke)->param_count; i >= 0; i--)
676 if (mspecs [i])
677 mono_metadata_free_marshal_spec (mspecs [i]);
678 g_free (mspecs);
679 g_free (sig);
680 }
681
682 MONO_HANDLE_ASSIGN (d, MONO_HANDLE_NEW (MonoDelegate, mono_object_new_checked (mono_domain_get (), klass, error)));
683 goto_if_nok (error, leave);
684 gpointer compiled_ptr = mono_compile_method_checked (wrapper, error);
685 goto_if_nok (error, leave);
686
687 mono_delegate_ctor_with_method (MONO_HANDLE_CAST (MonoObject, d), this_obj, compiled_ptr, wrapper, error);
688 goto_if_nok (error, leave);
689 }
690
691 g_assert (!MONO_HANDLE_IS_NULL (d));
692 if (MONO_HANDLE_DOMAIN (d) != mono_domain_get ())
693 mono_error_set_not_supported (error, "Delegates cannot be marshalled from native code into a domain other than their home domain");
694
695 leave:
696 HANDLE_FUNCTION_RETURN_REF (MonoDelegate, d);
697 }
698
699 void
mono_delegate_free_ftnptr(MonoDelegate * delegate)700 mono_delegate_free_ftnptr (MonoDelegate *delegate)
701 {
702 MonoJitInfo *ji;
703 void *ptr;
704
705 delegate_hash_table_remove (delegate);
706
707 ptr = (gpointer)mono_atomic_xchg_ptr (&delegate->delegate_trampoline, NULL);
708
709 if (!delegate->target) {
710 /* The wrapper method is shared between delegates -> no need to free it */
711 return;
712 }
713
714 if (ptr) {
715 uint32_t gchandle;
716 void **method_data;
717 MonoMethod *method;
718
719 ji = mono_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (ptr));
720 g_assert (ji);
721
722 method = mono_jit_info_get_method (ji);
723 method_data = (void **)((MonoMethodWrapper*)method)->method_data;
724
725 /*the target gchandle is the first entry after size and the wrapper itself.*/
726 gchandle = GPOINTER_TO_UINT (method_data [2]);
727
728 if (gchandle)
729 mono_gchandle_free (gchandle);
730
731 mono_runtime_free_method (mono_object_domain (delegate), method);
732 }
733 }
734
735 /* This is a JIT icall, it sets the pending exception and returns NULL on error */
736 static MonoString *
mono_string_from_byvalstr(const char * data,int max_len)737 mono_string_from_byvalstr (const char *data, int max_len)
738 {
739 MonoError error;
740 MonoDomain *domain = mono_domain_get ();
741 int len = 0;
742
743 if (!data)
744 return NULL;
745
746 while (len < max_len - 1 && data [len])
747 len++;
748
749 MonoString *result = mono_string_new_len_checked (domain, data, len, &error);
750 mono_error_set_pending_exception (&error);
751 return result;
752 }
753
754 /* This is a JIT icall, it sets the pending exception and return NULL on error */
755 static MonoString *
mono_string_from_byvalwstr(gunichar2 * data,int max_len)756 mono_string_from_byvalwstr (gunichar2 *data, int max_len)
757 {
758 MonoError error;
759 MonoString *res = NULL;
760 MonoDomain *domain = mono_domain_get ();
761 int len = 0;
762
763 if (!data)
764 return NULL;
765
766 while (data [len]) len++;
767
768 res = mono_string_new_utf16_checked (domain, data, MIN (len, max_len), &error);
769 if (!mono_error_ok (&error)) {
770 mono_error_set_pending_exception (&error);
771 return NULL;
772 }
773 return res;
774 }
775
776 gpointer
mono_array_to_savearray(MonoArray * array)777 mono_array_to_savearray (MonoArray *array)
778 {
779 if (!array)
780 return NULL;
781
782 g_assert_not_reached ();
783 return NULL;
784 }
785
786 gpointer
mono_array_to_lparray(MonoArray * array)787 mono_array_to_lparray (MonoArray *array)
788 {
789 #ifndef DISABLE_COM
790 gpointer *nativeArray = NULL;
791 int nativeArraySize = 0;
792
793 int i = 0;
794 MonoClass *klass;
795 MonoError error;
796 #endif
797
798 if (!array)
799 return NULL;
800 #ifndef DISABLE_COM
801 error_init (&error);
802 klass = array->obj.vtable->klass;
803
804 switch (klass->element_class->byval_arg.type) {
805 case MONO_TYPE_VOID:
806 g_assert_not_reached ();
807 break;
808 case MONO_TYPE_CLASS:
809 nativeArraySize = array->max_length;
810 nativeArray = (void **)g_malloc (sizeof(gpointer) * nativeArraySize);
811 for(i = 0; i < nativeArraySize; ++i) {
812 nativeArray[i] = mono_cominterop_get_com_interface (((MonoObject **)array->vector)[i], klass->element_class, &error);
813 if (mono_error_set_pending_exception (&error))
814 break;
815 }
816 return nativeArray;
817 case MONO_TYPE_U1:
818 case MONO_TYPE_BOOLEAN:
819 case MONO_TYPE_I1:
820 case MONO_TYPE_U2:
821 case MONO_TYPE_CHAR:
822 case MONO_TYPE_I2:
823 case MONO_TYPE_I:
824 case MONO_TYPE_U:
825 case MONO_TYPE_I4:
826 case MONO_TYPE_U4:
827 case MONO_TYPE_U8:
828 case MONO_TYPE_I8:
829 case MONO_TYPE_R4:
830 case MONO_TYPE_R8:
831 case MONO_TYPE_VALUETYPE:
832 case MONO_TYPE_PTR:
833 /* nothing to do */
834 break;
835 case MONO_TYPE_GENERICINST:
836 case MONO_TYPE_OBJECT:
837 case MONO_TYPE_ARRAY:
838 case MONO_TYPE_SZARRAY:
839 case MONO_TYPE_STRING:
840 default:
841 g_warning ("type 0x%x not handled", klass->element_class->byval_arg.type);
842 g_assert_not_reached ();
843 }
844 #endif
845 return array->vector;
846 }
847
848 void
mono_free_lparray(MonoArray * array,gpointer * nativeArray)849 mono_free_lparray (MonoArray *array, gpointer* nativeArray)
850 {
851 #ifndef DISABLE_COM
852 MonoClass *klass;
853
854 if (!array)
855 return;
856
857 if (!nativeArray)
858 return;
859 klass = array->obj.vtable->klass;
860
861 if (klass->element_class->byval_arg.type == MONO_TYPE_CLASS)
862 g_free (nativeArray);
863 #endif
864 }
865
866 static void
mono_byvalarray_to_array(MonoArray * arr,gpointer native_arr,MonoClass * elclass,guint32 elnum)867 mono_byvalarray_to_array (MonoArray *arr, gpointer native_arr, MonoClass *elclass, guint32 elnum)
868 {
869 g_assert (arr->obj.vtable->klass->element_class == mono_defaults.char_class);
870
871 if (elclass == mono_defaults.byte_class) {
872 GError *error = NULL;
873 guint16 *ut;
874 glong items_written;
875
876 ut = g_utf8_to_utf16 ((const gchar *)native_arr, elnum, NULL, &items_written, &error);
877
878 if (!error) {
879 memcpy (mono_array_addr (arr, guint16, 0), ut, items_written * sizeof (guint16));
880 g_free (ut);
881 }
882 else
883 g_error_free (error);
884 }
885 else
886 g_assert_not_reached ();
887 }
888
889 static void
mono_byvalarray_to_byte_array(MonoArray * arr,gpointer native_arr,guint32 elnum)890 mono_byvalarray_to_byte_array (MonoArray *arr, gpointer native_arr, guint32 elnum)
891 {
892 mono_byvalarray_to_array (arr, native_arr, mono_defaults.byte_class, elnum);
893 }
894
895 /* This is a JIT icall, it sets the pending exception and returns on error */
896 static void
mono_array_to_byvalarray(gpointer native_arr,MonoArray * arr,MonoClass * elclass,guint32 elnum)897 mono_array_to_byvalarray (gpointer native_arr, MonoArray *arr, MonoClass *elclass, guint32 elnum)
898 {
899 g_assert (arr->obj.vtable->klass->element_class == mono_defaults.char_class);
900
901 if (elclass == mono_defaults.byte_class) {
902 char *as;
903 GError *error = NULL;
904
905 as = g_utf16_to_utf8 (mono_array_addr (arr, gunichar2, 0), mono_array_length (arr), NULL, NULL, &error);
906 if (error) {
907 mono_set_pending_exception (mono_get_exception_argument ("string", error->message));
908 g_error_free (error);
909 return;
910 }
911
912 memcpy (native_arr, as, MIN (strlen (as), elnum));
913 g_free (as);
914 } else {
915 g_assert_not_reached ();
916 }
917 }
918
919 static void
mono_array_to_byte_byvalarray(gpointer native_arr,MonoArray * arr,guint32 elnum)920 mono_array_to_byte_byvalarray (gpointer native_arr, MonoArray *arr, guint32 elnum)
921 {
922 mono_array_to_byvalarray (native_arr, arr, mono_defaults.byte_class, elnum);
923 }
924
925 static MonoStringBuilder *
mono_string_builder_new(int starting_string_length)926 mono_string_builder_new (int starting_string_length)
927 {
928 static MonoClass *string_builder_class;
929 static MonoMethod *sb_ctor;
930 static void *args [1];
931
932 MonoError error;
933 int initial_len = starting_string_length;
934
935 if (initial_len < 0)
936 initial_len = 0;
937
938 if (!sb_ctor) {
939 MonoMethodDesc *desc;
940 MonoMethod *m;
941
942 string_builder_class = mono_class_get_string_builder_class ();
943 g_assert (string_builder_class);
944 desc = mono_method_desc_new (":.ctor(int)", FALSE);
945 m = mono_method_desc_search_in_class (desc, string_builder_class);
946 g_assert (m);
947 mono_method_desc_free (desc);
948 mono_memory_barrier ();
949 sb_ctor = m;
950 }
951
952 // We make a new array in the _to_builder function, so this
953 // array will always be garbage collected.
954 args [0] = &initial_len;
955
956 MonoStringBuilder *sb = (MonoStringBuilder*)mono_object_new_checked (mono_domain_get (), string_builder_class, &error);
957 mono_error_assert_ok (&error);
958
959 MonoObject *exc;
960 mono_runtime_try_invoke (sb_ctor, sb, args, &exc, &error);
961 g_assert (exc == NULL);
962 mono_error_assert_ok (&error);
963
964 g_assert (sb->chunkChars->max_length >= initial_len);
965
966 return sb;
967 }
968
969 static void
mono_string_utf16_to_builder_copy(MonoStringBuilder * sb,gunichar2 * text,size_t string_len)970 mono_string_utf16_to_builder_copy (MonoStringBuilder *sb, gunichar2 *text, size_t string_len)
971 {
972 gunichar2 *charDst = (gunichar2 *)sb->chunkChars->vector;
973 gunichar2 *charSrc = (gunichar2 *)text;
974 memcpy (charDst, charSrc, sizeof (gunichar2) * string_len);
975
976 sb->chunkLength = string_len;
977
978 return;
979 }
980
981 MonoStringBuilder *
mono_string_utf16_to_builder2(gunichar2 * text)982 mono_string_utf16_to_builder2 (gunichar2 *text)
983 {
984 if (!text)
985 return NULL;
986
987 int len;
988 for (len = 0; text [len] != 0; ++len);
989
990 MonoStringBuilder *sb = mono_string_builder_new (len);
991 mono_string_utf16_to_builder (sb, text);
992
993 return sb;
994 }
995
996 void
mono_string_utf8_to_builder(MonoStringBuilder * sb,char * text)997 mono_string_utf8_to_builder (MonoStringBuilder *sb, char *text)
998 {
999 if (!sb || !text)
1000 return;
1001
1002 GError *error = NULL;
1003 glong copied;
1004 gunichar2* ut = g_utf8_to_utf16 (text, strlen (text), NULL, &copied, &error);
1005 int capacity = mono_string_builder_capacity (sb);
1006
1007 if (copied > capacity)
1008 copied = capacity;
1009
1010 if (!error) {
1011 MONO_OBJECT_SETREF (sb, chunkPrevious, NULL);
1012 mono_string_utf16_to_builder_copy (sb, ut, copied);
1013 } else
1014 g_error_free (error);
1015
1016 g_free (ut);
1017 }
1018
1019 MonoStringBuilder *
mono_string_utf8_to_builder2(char * text)1020 mono_string_utf8_to_builder2 (char *text)
1021 {
1022 if (!text)
1023 return NULL;
1024
1025 int len = strlen (text);
1026 MonoStringBuilder *sb = mono_string_builder_new (len);
1027 mono_string_utf8_to_builder (sb, text);
1028
1029 return sb;
1030 }
1031
1032 void
mono_string_utf16_to_builder(MonoStringBuilder * sb,gunichar2 * text)1033 mono_string_utf16_to_builder (MonoStringBuilder *sb, gunichar2 *text)
1034 {
1035 if (!sb || !text)
1036 return;
1037
1038 guint32 len;
1039 for (len = 0; text [len] != 0; ++len);
1040
1041 if (len > mono_string_builder_capacity (sb))
1042 len = mono_string_builder_capacity (sb);
1043
1044 mono_string_utf16_to_builder_copy (sb, text, len);
1045 }
1046
1047 /**
1048 * mono_string_builder_to_utf8:
1049 * \param sb the string builder
1050 *
1051 * Converts to utf8 the contents of the \c MonoStringBuilder .
1052 *
1053 * \returns a utf8 string with the contents of the \c StringBuilder .
1054 *
1055 * The return value must be released with mono_marshal_free.
1056 *
1057 * This is a JIT icall, it sets the pending exception and returns NULL on error.
1058 */
1059 gchar*
mono_string_builder_to_utf8(MonoStringBuilder * sb)1060 mono_string_builder_to_utf8 (MonoStringBuilder *sb)
1061 {
1062 MonoError error;
1063 GError *gerror = NULL;
1064 glong byte_count;
1065 if (!sb)
1066 return NULL;
1067
1068 gunichar2 *str_utf16 = mono_string_builder_to_utf16 (sb);
1069
1070 guint str_len = mono_string_builder_string_length (sb);
1071
1072 gchar *tmp = g_utf16_to_utf8 (str_utf16, str_len, NULL, &byte_count, &gerror);
1073
1074 if (gerror) {
1075 g_error_free (gerror);
1076 mono_marshal_free (str_utf16);
1077 mono_set_pending_exception (mono_get_exception_execution_engine ("Failed to convert StringBuilder from utf16 to utf8"));
1078 return NULL;
1079 } else {
1080 guint len = mono_string_builder_capacity (sb) + 1;
1081 gchar *res = (gchar *)mono_marshal_alloc (MAX (byte_count+1, len * sizeof (gchar)), &error);
1082 if (!mono_error_ok (&error)) {
1083 mono_marshal_free (str_utf16);
1084 g_free (tmp);
1085 mono_error_set_pending_exception (&error);
1086 return NULL;
1087 }
1088
1089 memcpy (res, tmp, byte_count);
1090 res[byte_count] = '\0';
1091
1092 mono_marshal_free (str_utf16);
1093 g_free (tmp);
1094 return res;
1095 }
1096 }
1097
1098 /**
1099 * mono_string_builder_to_utf16:
1100 * \param sb the string builder
1101 *
1102 * Converts to utf16 the contents of the \c MonoStringBuilder .
1103 *
1104 * Returns: a utf16 string with the contents of the \c StringBuilder .
1105 *
1106 * The return value must be released with mono_marshal_free.
1107 *
1108 * This is a JIT icall, it sets the pending exception and returns NULL on error.
1109 */
1110 gunichar2*
mono_string_builder_to_utf16(MonoStringBuilder * sb)1111 mono_string_builder_to_utf16 (MonoStringBuilder *sb)
1112 {
1113 MonoError error;
1114
1115 if (!sb)
1116 return NULL;
1117
1118 g_assert (sb->chunkChars);
1119
1120 guint len = mono_string_builder_capacity (sb);
1121
1122 if (len == 0)
1123 len = 1;
1124
1125 gunichar2 *str = (gunichar2 *)mono_marshal_alloc ((len + 1) * sizeof (gunichar2), &error);
1126 if (!mono_error_ok (&error)) {
1127 mono_error_set_pending_exception (&error);
1128 return NULL;
1129 }
1130
1131 str[len] = '\0';
1132
1133 if (len == 0)
1134 return str;
1135
1136 MonoStringBuilder* chunk = sb;
1137 do {
1138 if (chunk->chunkLength > 0) {
1139 // Check that we will not overrun our boundaries.
1140 gunichar2 *source = (gunichar2 *)chunk->chunkChars->vector;
1141
1142 if (chunk->chunkLength <= len) {
1143 memcpy (str + chunk->chunkOffset, source, chunk->chunkLength * sizeof(gunichar2));
1144 } else {
1145 g_error ("A chunk in the StringBuilder had a length longer than expected from the offset.");
1146 }
1147
1148 len -= chunk->chunkLength;
1149 }
1150 chunk = chunk->chunkPrevious;
1151 } while (chunk != NULL);
1152
1153 return str;
1154 }
1155
1156 #ifndef HOST_WIN32
1157 /* This is a JIT icall, it sets the pending exception and returns NULL on error. */
1158 static gpointer
mono_string_to_utf8str(MonoString * s)1159 mono_string_to_utf8str (MonoString *s)
1160 {
1161 MonoError error;
1162 char *result = mono_string_to_utf8_checked (s, &error);
1163 mono_error_set_pending_exception (&error);
1164 return result;
1165 }
1166 #endif
1167
1168 gpointer
mono_string_to_ansibstr(MonoString * string_obj)1169 mono_string_to_ansibstr (MonoString *string_obj)
1170 {
1171 g_error ("UnmanagedMarshal.BStr is not implemented.");
1172 return NULL;
1173 }
1174
1175 /**
1176 * mono_string_to_byvalstr:
1177 * \param dst Where to store the null-terminated utf8 decoded string.
1178 * \param src the \c MonoString to copy.
1179 * \param size the maximum number of bytes to copy.
1180 *
1181 * Copies the \c MonoString pointed to by \p src as a utf8 string
1182 * into \p dst, it copies at most \p size bytes into the destination.
1183 */
1184 void
mono_string_to_byvalstr(gpointer dst,MonoString * src,int size)1185 mono_string_to_byvalstr (gpointer dst, MonoString *src, int size)
1186 {
1187 MonoError error;
1188 char *s;
1189 int len;
1190
1191 g_assert (dst != NULL);
1192 g_assert (size > 0);
1193
1194 memset (dst, 0, size);
1195 if (!src)
1196 return;
1197
1198 s = mono_string_to_utf8_checked (src, &error);
1199 if (mono_error_set_pending_exception (&error))
1200 return;
1201 len = MIN (size, strlen (s));
1202 if (len >= size)
1203 len--;
1204 memcpy (dst, s, len);
1205 g_free (s);
1206 }
1207
1208 /**
1209 * mono_string_to_byvalwstr:
1210 * \param dst Where to store the null-terminated utf16 decoded string.
1211 * \param src the \c MonoString to copy.
1212 * \param size the maximum number of wide characters to copy (each consumes 2 bytes)
1213 *
1214 * Copies the \c MonoString pointed to by \p src as a utf16 string into
1215 * \p dst, it copies at most \p size bytes into the destination (including
1216 * a terminating 16-bit zero terminator).
1217 */
1218 void
mono_string_to_byvalwstr(gpointer dst,MonoString * src,int size)1219 mono_string_to_byvalwstr (gpointer dst, MonoString *src, int size)
1220 {
1221 int len;
1222
1223 g_assert (dst != NULL);
1224 g_assert (size > 1);
1225
1226 if (!src) {
1227 memset (dst, 0, size * 2);
1228 return;
1229 }
1230
1231 len = MIN (size, (mono_string_length (src)));
1232 memcpy (dst, mono_string_chars (src), len * 2);
1233 if (size <= mono_string_length (src))
1234 len--;
1235 *((gunichar2 *) dst + len) = 0;
1236 }
1237
1238 /* this is an icall, it sets the pending exception and returns NULL on error */
1239 static MonoString*
mono_string_new_len_wrapper(const char * text,guint length)1240 mono_string_new_len_wrapper (const char *text, guint length)
1241 {
1242 MonoError error;
1243 MonoString *result = mono_string_new_len_checked (mono_domain_get (), text, length, &error);
1244 mono_error_set_pending_exception (&error);
1245 return result;
1246 }
1247
1248 #ifdef ENABLE_ILGEN
1249
1250 /*
1251 * mono_mb_emit_exception_marshal_directive:
1252 *
1253 * This function assumes ownership of MSG, which should be malloc-ed.
1254 */
1255 static void
mono_mb_emit_exception_marshal_directive(MonoMethodBuilder * mb,char * msg)1256 mono_mb_emit_exception_marshal_directive (MonoMethodBuilder *mb, char *msg)
1257 {
1258 char *s;
1259
1260 if (!mb->dynamic) {
1261 s = mono_image_strdup (mb->method->klass->image, msg);
1262 g_free (msg);
1263 } else {
1264 s = g_strdup (msg);
1265 }
1266 mono_mb_emit_exception_full (mb, "System.Runtime.InteropServices", "MarshalDirectiveException", s);
1267 }
1268 #endif /* ENABLE_ILGEN */
1269
1270 guint
mono_type_to_ldind(MonoType * type)1271 mono_type_to_ldind (MonoType *type)
1272 {
1273 if (type->byref)
1274 return CEE_LDIND_I;
1275
1276 handle_enum:
1277 switch (type->type) {
1278 case MONO_TYPE_I1:
1279 return CEE_LDIND_I1;
1280 case MONO_TYPE_U1:
1281 case MONO_TYPE_BOOLEAN:
1282 return CEE_LDIND_U1;
1283 case MONO_TYPE_I2:
1284 return CEE_LDIND_I2;
1285 case MONO_TYPE_U2:
1286 case MONO_TYPE_CHAR:
1287 return CEE_LDIND_U2;
1288 case MONO_TYPE_I4:
1289 return CEE_LDIND_I4;
1290 case MONO_TYPE_U4:
1291 return CEE_LDIND_U4;
1292 case MONO_TYPE_I:
1293 case MONO_TYPE_U:
1294 case MONO_TYPE_PTR:
1295 case MONO_TYPE_FNPTR:
1296 return CEE_LDIND_I;
1297 case MONO_TYPE_CLASS:
1298 case MONO_TYPE_STRING:
1299 case MONO_TYPE_OBJECT:
1300 case MONO_TYPE_SZARRAY:
1301 case MONO_TYPE_ARRAY:
1302 return CEE_LDIND_REF;
1303 case MONO_TYPE_I8:
1304 case MONO_TYPE_U8:
1305 return CEE_LDIND_I8;
1306 case MONO_TYPE_R4:
1307 return CEE_LDIND_R4;
1308 case MONO_TYPE_R8:
1309 return CEE_LDIND_R8;
1310 case MONO_TYPE_VALUETYPE:
1311 if (type->data.klass->enumtype) {
1312 type = mono_class_enum_basetype (type->data.klass);
1313 goto handle_enum;
1314 }
1315 return CEE_LDOBJ;
1316 case MONO_TYPE_TYPEDBYREF:
1317 return CEE_LDOBJ;
1318 case MONO_TYPE_GENERICINST:
1319 type = &type->data.generic_class->container_class->byval_arg;
1320 goto handle_enum;
1321 default:
1322 g_error ("unknown type 0x%02x in type_to_ldind", type->type);
1323 }
1324 return -1;
1325 }
1326
1327 guint
mono_type_to_stind(MonoType * type)1328 mono_type_to_stind (MonoType *type)
1329 {
1330 if (type->byref)
1331 return MONO_TYPE_IS_REFERENCE (type) ? CEE_STIND_REF : CEE_STIND_I;
1332
1333
1334 handle_enum:
1335 switch (type->type) {
1336 case MONO_TYPE_I1:
1337 case MONO_TYPE_U1:
1338 case MONO_TYPE_BOOLEAN:
1339 return CEE_STIND_I1;
1340 case MONO_TYPE_I2:
1341 case MONO_TYPE_U2:
1342 case MONO_TYPE_CHAR:
1343 return CEE_STIND_I2;
1344 case MONO_TYPE_I4:
1345 case MONO_TYPE_U4:
1346 return CEE_STIND_I4;
1347 case MONO_TYPE_I:
1348 case MONO_TYPE_U:
1349 case MONO_TYPE_PTR:
1350 case MONO_TYPE_FNPTR:
1351 return CEE_STIND_I;
1352 case MONO_TYPE_CLASS:
1353 case MONO_TYPE_STRING:
1354 case MONO_TYPE_OBJECT:
1355 case MONO_TYPE_SZARRAY:
1356 case MONO_TYPE_ARRAY:
1357 return CEE_STIND_REF;
1358 case MONO_TYPE_I8:
1359 case MONO_TYPE_U8:
1360 return CEE_STIND_I8;
1361 case MONO_TYPE_R4:
1362 return CEE_STIND_R4;
1363 case MONO_TYPE_R8:
1364 return CEE_STIND_R8;
1365 case MONO_TYPE_VALUETYPE:
1366 if (type->data.klass->enumtype) {
1367 type = mono_class_enum_basetype (type->data.klass);
1368 goto handle_enum;
1369 }
1370 return CEE_STOBJ;
1371 case MONO_TYPE_TYPEDBYREF:
1372 return CEE_STOBJ;
1373 case MONO_TYPE_GENERICINST:
1374 type = &type->data.generic_class->container_class->byval_arg;
1375 goto handle_enum;
1376 default:
1377 g_error ("unknown type 0x%02x in type_to_stind", type->type);
1378 }
1379 return -1;
1380 }
1381
1382 #ifdef ENABLE_ILGEN
1383
1384 static void
emit_ptr_to_object_conv(MonoMethodBuilder * mb,MonoType * type,MonoMarshalConv conv,MonoMarshalSpec * mspec)1385 emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
1386 {
1387 switch (conv) {
1388 case MONO_MARSHAL_CONV_BOOL_I4:
1389 mono_mb_emit_ldloc (mb, 1);
1390 mono_mb_emit_ldloc (mb, 0);
1391 mono_mb_emit_byte (mb, CEE_LDIND_I4);
1392 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
1393 mono_mb_emit_byte (mb, 3);
1394 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
1395 mono_mb_emit_byte (mb, CEE_BR_S);
1396 mono_mb_emit_byte (mb, 1);
1397 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1398 mono_mb_emit_byte (mb, CEE_STIND_I1);
1399 break;
1400 case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL:
1401 mono_mb_emit_ldloc (mb, 1);
1402 mono_mb_emit_ldloc (mb, 0);
1403 mono_mb_emit_byte (mb, CEE_LDIND_I2);
1404 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
1405 mono_mb_emit_byte (mb, 3);
1406 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
1407 mono_mb_emit_byte (mb, CEE_BR_S);
1408 mono_mb_emit_byte (mb, 1);
1409 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1410 mono_mb_emit_byte (mb, CEE_STIND_I1);
1411 break;
1412 case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: {
1413 MonoClass *eklass = NULL;
1414 int esize;
1415
1416 if (type->type == MONO_TYPE_SZARRAY) {
1417 eklass = type->data.klass;
1418 } else {
1419 g_assert_not_reached ();
1420 }
1421
1422 esize = mono_class_native_size (eklass, NULL);
1423
1424 /* create a new array */
1425 mono_mb_emit_ldloc (mb, 1);
1426 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
1427 mono_mb_emit_op (mb, CEE_NEWARR, eklass);
1428 mono_mb_emit_byte (mb, CEE_STIND_REF);
1429
1430 if (eklass->blittable) {
1431 /* copy the elements */
1432 mono_mb_emit_ldloc (mb, 1);
1433 mono_mb_emit_byte (mb, CEE_LDIND_I);
1434 mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoArray, vector));
1435 mono_mb_emit_byte (mb, CEE_ADD);
1436 mono_mb_emit_ldloc (mb, 0);
1437 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem * esize);
1438 mono_mb_emit_byte (mb, CEE_PREFIX1);
1439 mono_mb_emit_byte (mb, CEE_CPBLK);
1440 }
1441 else {
1442 int array_var, src_var, dst_var, index_var;
1443 guint32 label2, label3;
1444
1445 array_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1446 src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1447 dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1448
1449 /* set array_var */
1450 mono_mb_emit_ldloc (mb, 1);
1451 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1452 mono_mb_emit_stloc (mb, array_var);
1453
1454 /* save the old src pointer */
1455 mono_mb_emit_ldloc (mb, 0);
1456 mono_mb_emit_stloc (mb, src_var);
1457 /* save the old dst pointer */
1458 mono_mb_emit_ldloc (mb, 1);
1459 mono_mb_emit_stloc (mb, dst_var);
1460
1461 /* Emit marshalling loop */
1462 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1463 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1464 mono_mb_emit_stloc (mb, index_var);
1465
1466 /* Loop header */
1467 label2 = mono_mb_get_label (mb);
1468 mono_mb_emit_ldloc (mb, index_var);
1469 mono_mb_emit_ldloc (mb, array_var);
1470 mono_mb_emit_byte (mb, CEE_LDLEN);
1471 label3 = mono_mb_emit_branch (mb, CEE_BGE);
1472
1473 /* src is already set */
1474
1475 /* Set dst */
1476 mono_mb_emit_ldloc (mb, array_var);
1477 mono_mb_emit_ldloc (mb, index_var);
1478 mono_mb_emit_op (mb, CEE_LDELEMA, eklass);
1479 mono_mb_emit_stloc (mb, 1);
1480
1481 /* Do the conversion */
1482 emit_struct_conv (mb, eklass, TRUE);
1483
1484 /* Loop footer */
1485 mono_mb_emit_add_to_local (mb, index_var, 1);
1486
1487 mono_mb_emit_branch_label (mb, CEE_BR, label2);
1488
1489 mono_mb_patch_branch (mb, label3);
1490
1491 /* restore the old src pointer */
1492 mono_mb_emit_ldloc (mb, src_var);
1493 mono_mb_emit_stloc (mb, 0);
1494 /* restore the old dst pointer */
1495 mono_mb_emit_ldloc (mb, dst_var);
1496 mono_mb_emit_stloc (mb, 1);
1497 }
1498 break;
1499 }
1500 case MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY: {
1501 MonoClass *eclass = mono_defaults.char_class;
1502
1503 /* create a new array */
1504 mono_mb_emit_ldloc (mb, 1);
1505 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
1506 mono_mb_emit_op (mb, CEE_NEWARR, eclass);
1507 mono_mb_emit_byte (mb, CEE_STIND_REF);
1508
1509 mono_mb_emit_ldloc (mb, 1);
1510 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1511 mono_mb_emit_ldloc (mb, 0);
1512 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
1513 mono_mb_emit_icall (mb, mono_byvalarray_to_byte_array);
1514 break;
1515 }
1516 case MONO_MARSHAL_CONV_STR_BYVALSTR:
1517 if (mspec && mspec->native == MONO_NATIVE_BYVALTSTR && mspec->data.array_data.num_elem) {
1518 mono_mb_emit_ldloc (mb, 1);
1519 mono_mb_emit_ldloc (mb, 0);
1520 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
1521 mono_mb_emit_icall (mb, mono_string_from_byvalstr);
1522 } else {
1523 mono_mb_emit_ldloc (mb, 1);
1524 mono_mb_emit_ldloc (mb, 0);
1525 mono_mb_emit_icall (mb, ves_icall_string_new_wrapper);
1526 }
1527 mono_mb_emit_byte (mb, CEE_STIND_REF);
1528 break;
1529 case MONO_MARSHAL_CONV_STR_BYVALWSTR:
1530 if (mspec && mspec->native == MONO_NATIVE_BYVALTSTR && mspec->data.array_data.num_elem) {
1531 mono_mb_emit_ldloc (mb, 1);
1532 mono_mb_emit_ldloc (mb, 0);
1533 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
1534 mono_mb_emit_icall (mb, mono_string_from_byvalwstr);
1535 } else {
1536 mono_mb_emit_ldloc (mb, 1);
1537 mono_mb_emit_ldloc (mb, 0);
1538 mono_mb_emit_icall (mb, ves_icall_mono_string_from_utf16);
1539 }
1540 mono_mb_emit_byte (mb, CEE_STIND_REF);
1541 break;
1542 case MONO_MARSHAL_CONV_STR_LPTSTR:
1543 mono_mb_emit_ldloc (mb, 1);
1544 mono_mb_emit_ldloc (mb, 0);
1545 mono_mb_emit_byte (mb, CEE_LDIND_I);
1546 #ifdef TARGET_WIN32
1547 mono_mb_emit_icall (mb, ves_icall_mono_string_from_utf16);
1548 #else
1549 mono_mb_emit_icall (mb, ves_icall_string_new_wrapper);
1550 #endif
1551 mono_mb_emit_byte (mb, CEE_STIND_REF);
1552 break;
1553
1554 // In Mono historically LPSTR was treated as a UTF8STR
1555 case MONO_MARSHAL_CONV_STR_LPSTR:
1556 case MONO_MARSHAL_CONV_STR_UTF8STR:
1557 mono_mb_emit_ldloc (mb, 1);
1558 mono_mb_emit_ldloc (mb, 0);
1559 mono_mb_emit_byte (mb, CEE_LDIND_I);
1560 mono_mb_emit_icall (mb, ves_icall_string_new_wrapper);
1561 mono_mb_emit_byte (mb, CEE_STIND_REF);
1562 break;
1563 case MONO_MARSHAL_CONV_STR_LPWSTR:
1564 mono_mb_emit_ldloc (mb, 1);
1565 mono_mb_emit_ldloc (mb, 0);
1566 mono_mb_emit_byte (mb, CEE_LDIND_I);
1567 mono_mb_emit_icall (mb, ves_icall_mono_string_from_utf16);
1568 mono_mb_emit_byte (mb, CEE_STIND_REF);
1569 break;
1570 case MONO_MARSHAL_CONV_OBJECT_STRUCT: {
1571 MonoClass *klass = mono_class_from_mono_type (type);
1572 int src_var, dst_var;
1573
1574 src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1575 dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1576
1577 /* *dst = new object */
1578 mono_mb_emit_ldloc (mb, 1);
1579 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1580 mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass);
1581 mono_mb_emit_byte (mb, CEE_STIND_REF);
1582
1583 /* save the old src pointer */
1584 mono_mb_emit_ldloc (mb, 0);
1585 mono_mb_emit_stloc (mb, src_var);
1586 /* save the old dst pointer */
1587 mono_mb_emit_ldloc (mb, 1);
1588 mono_mb_emit_stloc (mb, dst_var);
1589
1590 /* dst = pointer to newly created object data */
1591 mono_mb_emit_ldloc (mb, 1);
1592 mono_mb_emit_byte (mb, CEE_LDIND_I);
1593 mono_mb_emit_icon (mb, sizeof (MonoObject));
1594 mono_mb_emit_byte (mb, CEE_ADD);
1595 mono_mb_emit_stloc (mb, 1);
1596
1597 emit_struct_conv (mb, klass, TRUE);
1598
1599 /* restore the old src pointer */
1600 mono_mb_emit_ldloc (mb, src_var);
1601 mono_mb_emit_stloc (mb, 0);
1602 /* restore the old dst pointer */
1603 mono_mb_emit_ldloc (mb, dst_var);
1604 mono_mb_emit_stloc (mb, 1);
1605 break;
1606 }
1607 case MONO_MARSHAL_CONV_DEL_FTN: {
1608 MonoClass *klass = mono_class_from_mono_type (type);
1609
1610 mono_mb_emit_ldloc (mb, 1);
1611 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
1612 mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
1613 mono_mb_emit_ldloc (mb, 0);
1614 mono_mb_emit_byte (mb, CEE_LDIND_I);
1615 mono_mb_emit_icall (mb, mono_ftnptr_to_delegate);
1616 mono_mb_emit_byte (mb, CEE_STIND_REF);
1617 break;
1618 }
1619 case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
1620 g_error ("Structure field of type %s can't be marshalled as LPArray", mono_class_from_mono_type (type)->name);
1621 break;
1622
1623 #ifndef DISABLE_COM
1624 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
1625 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
1626 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
1627 mono_cominterop_emit_ptr_to_object_conv (mb, type, conv, mspec);
1628 break;
1629 #endif /* DISABLE_COM */
1630
1631 case MONO_MARSHAL_CONV_SAFEHANDLE: {
1632 /*
1633 * Passing SafeHandles as ref does not allow the unmanaged code
1634 * to change the SafeHandle value. If the value is changed,
1635 * we should issue a diagnostic exception (NotSupportedException)
1636 * that informs the user that changes to handles in unmanaged code
1637 * is not supported.
1638 *
1639 * Since we currently have no access to the original
1640 * SafeHandle that was used during the marshalling,
1641 * for now we just ignore this, and ignore/discard any
1642 * changes that might have happened to the handle.
1643 */
1644 break;
1645 }
1646
1647 case MONO_MARSHAL_CONV_HANDLEREF: {
1648 /*
1649 * Passing HandleRefs in a struct that is ref()ed does not
1650 * copy the values back to the HandleRef
1651 */
1652 break;
1653 }
1654
1655 case MONO_MARSHAL_CONV_STR_BSTR:
1656 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
1657 case MONO_MARSHAL_CONV_STR_TBSTR:
1658 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
1659 default: {
1660 char *msg = g_strdup_printf ("marshaling conversion %d not implemented", conv);
1661
1662 mono_mb_emit_exception_marshal_directive (mb, msg);
1663 break;
1664 }
1665 }
1666 }
1667
1668 static gpointer
conv_to_icall(MonoMarshalConv conv,int * ind_store_type)1669 conv_to_icall (MonoMarshalConv conv, int *ind_store_type)
1670 {
1671 int dummy;
1672 if (!ind_store_type)
1673 ind_store_type = &dummy;
1674 *ind_store_type = CEE_STIND_I;
1675 switch (conv) {
1676 case MONO_MARSHAL_CONV_STR_LPWSTR:
1677 return mono_marshal_string_to_utf16;
1678 case MONO_MARSHAL_CONV_LPWSTR_STR:
1679 *ind_store_type = CEE_STIND_REF;
1680 return ves_icall_mono_string_from_utf16;
1681 case MONO_MARSHAL_CONV_LPTSTR_STR:
1682 *ind_store_type = CEE_STIND_REF;
1683 return ves_icall_string_new_wrapper;
1684 case MONO_MARSHAL_CONV_UTF8STR_STR:
1685 case MONO_MARSHAL_CONV_LPSTR_STR:
1686 *ind_store_type = CEE_STIND_REF;
1687 return ves_icall_string_new_wrapper;
1688 case MONO_MARSHAL_CONV_STR_LPTSTR:
1689 #ifdef TARGET_WIN32
1690 return mono_marshal_string_to_utf16;
1691 #else
1692 return mono_string_to_utf8str;
1693 #endif
1694 // In Mono historically LPSTR was treated as a UTF8STR
1695 case MONO_MARSHAL_CONV_STR_UTF8STR:
1696 case MONO_MARSHAL_CONV_STR_LPSTR:
1697 return mono_string_to_utf8str;
1698 case MONO_MARSHAL_CONV_STR_BSTR:
1699 return mono_string_to_bstr;
1700 case MONO_MARSHAL_CONV_BSTR_STR:
1701 *ind_store_type = CEE_STIND_REF;
1702 return mono_string_from_bstr_icall;
1703 case MONO_MARSHAL_CONV_STR_TBSTR:
1704 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
1705 return mono_string_to_ansibstr;
1706 case MONO_MARSHAL_CONV_SB_UTF8STR:
1707 case MONO_MARSHAL_CONV_SB_LPSTR:
1708 return mono_string_builder_to_utf8;
1709 case MONO_MARSHAL_CONV_SB_LPTSTR:
1710 #ifdef TARGET_WIN32
1711 return mono_string_builder_to_utf16;
1712 #else
1713 return mono_string_builder_to_utf8;
1714 #endif
1715 case MONO_MARSHAL_CONV_SB_LPWSTR:
1716 return mono_string_builder_to_utf16;
1717 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
1718 return mono_array_to_savearray;
1719 case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
1720 return mono_array_to_lparray;
1721 case MONO_MARSHAL_FREE_LPARRAY:
1722 return mono_free_lparray;
1723 case MONO_MARSHAL_CONV_DEL_FTN:
1724 return mono_delegate_to_ftnptr;
1725 case MONO_MARSHAL_CONV_FTN_DEL:
1726 *ind_store_type = CEE_STIND_REF;
1727 return mono_ftnptr_to_delegate;
1728 case MONO_MARSHAL_CONV_UTF8STR_SB:
1729 case MONO_MARSHAL_CONV_LPSTR_SB:
1730 *ind_store_type = CEE_STIND_REF;
1731 return mono_string_utf8_to_builder;
1732 case MONO_MARSHAL_CONV_LPTSTR_SB:
1733 *ind_store_type = CEE_STIND_REF;
1734 #ifdef TARGET_WIN32
1735 return mono_string_utf16_to_builder;
1736 #else
1737 return mono_string_utf8_to_builder;
1738 #endif
1739 case MONO_MARSHAL_CONV_LPWSTR_SB:
1740 *ind_store_type = CEE_STIND_REF;
1741 return mono_string_utf16_to_builder;
1742 case MONO_MARSHAL_FREE_ARRAY:
1743 return mono_marshal_free_array;
1744 case MONO_MARSHAL_CONV_STR_BYVALSTR:
1745 return mono_string_to_byvalstr;
1746 case MONO_MARSHAL_CONV_STR_BYVALWSTR:
1747 return mono_string_to_byvalwstr;
1748 default:
1749 g_assert_not_reached ();
1750 }
1751
1752 return NULL;
1753 }
1754
1755 static void
emit_object_to_ptr_conv(MonoMethodBuilder * mb,MonoType * type,MonoMarshalConv conv,MonoMarshalSpec * mspec)1756 emit_object_to_ptr_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
1757 {
1758 int pos;
1759 int stind_op;
1760
1761 switch (conv) {
1762 case MONO_MARSHAL_CONV_BOOL_I4:
1763 mono_mb_emit_ldloc (mb, 1);
1764 mono_mb_emit_ldloc (mb, 0);
1765 mono_mb_emit_byte (mb, CEE_LDIND_U1);
1766 mono_mb_emit_byte (mb, CEE_STIND_I4);
1767 break;
1768 case MONO_MARSHAL_CONV_BOOL_VARIANTBOOL:
1769 mono_mb_emit_ldloc (mb, 1);
1770 mono_mb_emit_ldloc (mb, 0);
1771 mono_mb_emit_byte (mb, CEE_LDIND_U1);
1772 mono_mb_emit_byte (mb, CEE_NEG);
1773 mono_mb_emit_byte (mb, CEE_STIND_I2);
1774 break;
1775 // In Mono historically LPSTR was treated as a UTF8STR
1776 case MONO_MARSHAL_CONV_STR_UTF8STR:
1777 case MONO_MARSHAL_CONV_STR_LPWSTR:
1778 case MONO_MARSHAL_CONV_STR_LPSTR:
1779 case MONO_MARSHAL_CONV_STR_LPTSTR:
1780 case MONO_MARSHAL_CONV_STR_BSTR:
1781 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
1782 case MONO_MARSHAL_CONV_STR_TBSTR: {
1783 int pos;
1784
1785 /* free space if free == true */
1786 mono_mb_emit_ldloc (mb, 2);
1787 pos = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1788 mono_mb_emit_ldloc (mb, 1);
1789 mono_mb_emit_byte (mb, CEE_LDIND_I);
1790 mono_mb_emit_icall (mb, g_free);
1791 mono_mb_patch_short_branch (mb, pos);
1792
1793 mono_mb_emit_ldloc (mb, 1);
1794 mono_mb_emit_ldloc (mb, 0);
1795 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1796 mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
1797 mono_mb_emit_byte (mb, stind_op);
1798 break;
1799 }
1800 case MONO_MARSHAL_CONV_ARRAY_SAVEARRAY:
1801 case MONO_MARSHAL_CONV_ARRAY_LPARRAY:
1802 case MONO_MARSHAL_CONV_DEL_FTN:
1803 mono_mb_emit_ldloc (mb, 1);
1804 mono_mb_emit_ldloc (mb, 0);
1805 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1806 mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
1807 mono_mb_emit_byte (mb, stind_op);
1808 break;
1809 case MONO_MARSHAL_CONV_STR_BYVALSTR:
1810 case MONO_MARSHAL_CONV_STR_BYVALWSTR: {
1811 g_assert (mspec);
1812
1813 mono_mb_emit_ldloc (mb, 1); /* dst */
1814 mono_mb_emit_ldloc (mb, 0);
1815 mono_mb_emit_byte (mb, CEE_LDIND_REF); /* src String */
1816 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
1817 mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
1818 break;
1819 }
1820 case MONO_MARSHAL_CONV_ARRAY_BYVALARRAY: {
1821 MonoClass *eklass = NULL;
1822 int esize;
1823
1824 if (type->type == MONO_TYPE_SZARRAY) {
1825 eklass = type->data.klass;
1826 } else {
1827 g_assert_not_reached ();
1828 }
1829
1830 if (eklass->valuetype)
1831 esize = mono_class_native_size (eklass, NULL);
1832 else
1833 esize = sizeof (gpointer);
1834
1835 mono_mb_emit_ldloc (mb, 0);
1836 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1837 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
1838
1839 if (eklass->blittable) {
1840 mono_mb_emit_ldloc (mb, 1);
1841 mono_mb_emit_ldloc (mb, 0);
1842 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1843 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoArray, vector));
1844 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem * esize);
1845 mono_mb_emit_byte (mb, CEE_PREFIX1);
1846 mono_mb_emit_byte (mb, CEE_CPBLK);
1847 } else {
1848 int array_var, src_var, dst_var, index_var;
1849 guint32 label2, label3;
1850
1851 array_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
1852 src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1853 dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1854
1855 /* set array_var */
1856 mono_mb_emit_ldloc (mb, 0);
1857 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1858 mono_mb_emit_stloc (mb, array_var);
1859
1860 /* save the old src pointer */
1861 mono_mb_emit_ldloc (mb, 0);
1862 mono_mb_emit_stloc (mb, src_var);
1863 /* save the old dst pointer */
1864 mono_mb_emit_ldloc (mb, 1);
1865 mono_mb_emit_stloc (mb, dst_var);
1866
1867 /* Emit marshalling loop */
1868 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1869 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
1870 mono_mb_emit_stloc (mb, index_var);
1871
1872 /* Loop header */
1873 label2 = mono_mb_get_label (mb);
1874 mono_mb_emit_ldloc (mb, index_var);
1875 mono_mb_emit_ldloc (mb, array_var);
1876 mono_mb_emit_byte (mb, CEE_LDLEN);
1877 label3 = mono_mb_emit_branch (mb, CEE_BGE);
1878
1879 /* Set src */
1880 mono_mb_emit_ldloc (mb, array_var);
1881 mono_mb_emit_ldloc (mb, index_var);
1882 mono_mb_emit_op (mb, CEE_LDELEMA, eklass);
1883 mono_mb_emit_stloc (mb, 0);
1884
1885 /* dst is already set */
1886
1887 /* Do the conversion */
1888 emit_struct_conv (mb, eklass, FALSE);
1889
1890 /* Loop footer */
1891 mono_mb_emit_add_to_local (mb, index_var, 1);
1892
1893 mono_mb_emit_branch_label (mb, CEE_BR, label2);
1894
1895 mono_mb_patch_branch (mb, label3);
1896
1897 /* restore the old src pointer */
1898 mono_mb_emit_ldloc (mb, src_var);
1899 mono_mb_emit_stloc (mb, 0);
1900 /* restore the old dst pointer */
1901 mono_mb_emit_ldloc (mb, dst_var);
1902 mono_mb_emit_stloc (mb, 1);
1903 }
1904
1905 mono_mb_patch_branch (mb, pos);
1906 break;
1907 }
1908 case MONO_MARSHAL_CONV_ARRAY_BYVALCHARARRAY: {
1909 mono_mb_emit_ldloc (mb, 0);
1910 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1911 pos = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S);
1912
1913 mono_mb_emit_ldloc (mb, 1);
1914 mono_mb_emit_ldloc (mb, 0);
1915 mono_mb_emit_byte (mb, CEE_LDIND_REF);
1916 mono_mb_emit_icon (mb, mspec->data.array_data.num_elem);
1917 mono_mb_emit_icall (mb, mono_array_to_byte_byvalarray);
1918 mono_mb_patch_short_branch (mb, pos);
1919 break;
1920 }
1921 case MONO_MARSHAL_CONV_OBJECT_STRUCT: {
1922 int src_var, dst_var;
1923
1924 src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1925 dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
1926
1927 mono_mb_emit_ldloc (mb, 0);
1928 mono_mb_emit_byte (mb, CEE_LDIND_I);
1929 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
1930
1931 /* save the old src pointer */
1932 mono_mb_emit_ldloc (mb, 0);
1933 mono_mb_emit_stloc (mb, src_var);
1934 /* save the old dst pointer */
1935 mono_mb_emit_ldloc (mb, 1);
1936 mono_mb_emit_stloc (mb, dst_var);
1937
1938 /* src = pointer to object data */
1939 mono_mb_emit_ldloc (mb, 0);
1940 mono_mb_emit_byte (mb, CEE_LDIND_I);
1941 mono_mb_emit_icon (mb, sizeof (MonoObject));
1942 mono_mb_emit_byte (mb, CEE_ADD);
1943 mono_mb_emit_stloc (mb, 0);
1944
1945 emit_struct_conv (mb, mono_class_from_mono_type (type), FALSE);
1946
1947 /* restore the old src pointer */
1948 mono_mb_emit_ldloc (mb, src_var);
1949 mono_mb_emit_stloc (mb, 0);
1950 /* restore the old dst pointer */
1951 mono_mb_emit_ldloc (mb, dst_var);
1952 mono_mb_emit_stloc (mb, 1);
1953
1954 mono_mb_patch_branch (mb, pos);
1955 break;
1956 }
1957
1958 #ifndef DISABLE_COM
1959 case MONO_MARSHAL_CONV_OBJECT_INTERFACE:
1960 case MONO_MARSHAL_CONV_OBJECT_IDISPATCH:
1961 case MONO_MARSHAL_CONV_OBJECT_IUNKNOWN:
1962 mono_cominterop_emit_object_to_ptr_conv (mb, type, conv, mspec);
1963 break;
1964 #endif /* DISABLE_COM */
1965
1966 case MONO_MARSHAL_CONV_SAFEHANDLE: {
1967 int pos;
1968
1969 mono_mb_emit_ldloc (mb, 0);
1970 mono_mb_emit_byte (mb, CEE_LDIND_I);
1971 pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
1972 mono_mb_emit_exception (mb, "ArgumentNullException", NULL);
1973 mono_mb_patch_branch (mb, pos);
1974
1975 /* Pull the handle field from SafeHandle */
1976 mono_mb_emit_ldloc (mb, 1);
1977 mono_mb_emit_ldloc (mb, 0);
1978 mono_mb_emit_byte (mb, CEE_LDIND_I);
1979 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoSafeHandle, handle));
1980 mono_mb_emit_byte (mb, CEE_LDIND_I);
1981 mono_mb_emit_byte (mb, CEE_STIND_I);
1982 break;
1983 }
1984
1985 case MONO_MARSHAL_CONV_HANDLEREF: {
1986 mono_mb_emit_ldloc (mb, 1);
1987 mono_mb_emit_ldloc (mb, 0);
1988 mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoHandleRef, handle));
1989 mono_mb_emit_byte (mb, CEE_ADD);
1990 mono_mb_emit_byte (mb, CEE_LDIND_I);
1991 mono_mb_emit_byte (mb, CEE_STIND_I);
1992 break;
1993 }
1994
1995 default: {
1996 g_error ("marshalling conversion %d not implemented", conv);
1997 }
1998 }
1999 }
2000
2001 static int
offset_of_first_nonstatic_field(MonoClass * klass)2002 offset_of_first_nonstatic_field (MonoClass *klass)
2003 {
2004 int i;
2005 int fcount = mono_class_get_field_count (klass);
2006 mono_class_setup_fields (klass);
2007 for (i = 0; i < fcount; i++) {
2008 if (!(klass->fields[i].type->attrs & FIELD_ATTRIBUTE_STATIC) && !mono_field_is_deleted (&klass->fields[i]))
2009 return klass->fields[i].offset - sizeof (MonoObject);
2010 }
2011
2012 return 0;
2013 }
2014
2015 static gboolean
get_fixed_buffer_attr(MonoClassField * field,MonoType ** out_etype,int * out_len)2016 get_fixed_buffer_attr (MonoClassField *field, MonoType **out_etype, int *out_len)
2017 {
2018 MonoError error;
2019 MonoCustomAttrInfo *cinfo;
2020 MonoCustomAttrEntry *attr;
2021 int aindex;
2022
2023 cinfo = mono_custom_attrs_from_field_checked (field->parent, field, &error);
2024 if (!is_ok (&error))
2025 return FALSE;
2026 attr = NULL;
2027 if (cinfo) {
2028 for (aindex = 0; aindex < cinfo->num_attrs; ++aindex) {
2029 MonoClass *ctor_class = cinfo->attrs [aindex].ctor->klass;
2030 if (mono_class_has_parent (ctor_class, mono_class_get_fixed_buffer_attribute_class ())) {
2031 attr = &cinfo->attrs [aindex];
2032 break;
2033 }
2034 }
2035 }
2036 if (attr) {
2037 MonoArray *typed_args, *named_args;
2038 CattrNamedArg *arginfo;
2039 MonoObject *o;
2040
2041 mono_reflection_create_custom_attr_data_args (mono_defaults.corlib, attr->ctor, attr->data, attr->data_size, &typed_args, &named_args, &arginfo, &error);
2042 if (!is_ok (&error))
2043 return FALSE;
2044 g_assert (mono_array_length (typed_args) == 2);
2045
2046 /* typed args */
2047 o = mono_array_get (typed_args, MonoObject*, 0);
2048 *out_etype = monotype_cast (o)->type;
2049 o = mono_array_get (typed_args, MonoObject*, 1);
2050 g_assert (o->vtable->klass == mono_defaults.int32_class);
2051 *out_len = *(gint32*)mono_object_unbox (o);
2052 g_free (arginfo);
2053 }
2054 if (cinfo && !cinfo->cached)
2055 mono_custom_attrs_free (cinfo);
2056 return attr != NULL;
2057 }
2058
2059 static void
emit_fixed_buf_conv(MonoMethodBuilder * mb,MonoType * type,MonoType * etype,int len,gboolean to_object,int * out_usize)2060 emit_fixed_buf_conv (MonoMethodBuilder *mb, MonoType *type, MonoType *etype, int len, gboolean to_object, int *out_usize)
2061 {
2062 MonoClass *klass = mono_class_from_mono_type (type);
2063 MonoClass *eklass = mono_class_from_mono_type (etype);
2064 int esize;
2065
2066 esize = mono_class_native_size (eklass, NULL);
2067
2068 MonoMarshalNative string_encoding = klass->unicode ? MONO_NATIVE_LPWSTR : MONO_NATIVE_LPSTR;
2069 int usize = mono_class_value_size (eklass, NULL);
2070 int msize = mono_class_value_size (eklass, NULL);
2071
2072 //printf ("FIXED: %s %d %d\n", mono_type_full_name (type), eklass->blittable, string_encoding);
2073
2074 if (eklass->blittable) {
2075 /* copy the elements */
2076 mono_mb_emit_ldloc (mb, 1);
2077 mono_mb_emit_ldloc (mb, 0);
2078 mono_mb_emit_icon (mb, len * esize);
2079 mono_mb_emit_byte (mb, CEE_PREFIX1);
2080 mono_mb_emit_byte (mb, CEE_CPBLK);
2081 } else {
2082 int index_var;
2083 guint32 label2, label3;
2084
2085 /* Emit marshalling loop */
2086 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2087 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
2088 mono_mb_emit_stloc (mb, index_var);
2089
2090 /* Loop header */
2091 label2 = mono_mb_get_label (mb);
2092 mono_mb_emit_ldloc (mb, index_var);
2093 mono_mb_emit_icon (mb, len);
2094 label3 = mono_mb_emit_branch (mb, CEE_BGE);
2095
2096 /* src/dst is already set */
2097
2098 /* Do the conversion */
2099 MonoTypeEnum t = etype->type;
2100 switch (t) {
2101 case MONO_TYPE_I4:
2102 case MONO_TYPE_U4:
2103 case MONO_TYPE_I1:
2104 case MONO_TYPE_U1:
2105 case MONO_TYPE_BOOLEAN:
2106 case MONO_TYPE_I2:
2107 case MONO_TYPE_U2:
2108 case MONO_TYPE_CHAR:
2109 case MONO_TYPE_I8:
2110 case MONO_TYPE_U8:
2111 case MONO_TYPE_PTR:
2112 case MONO_TYPE_R4:
2113 case MONO_TYPE_R8:
2114 mono_mb_emit_ldloc (mb, 1);
2115 mono_mb_emit_ldloc (mb, 0);
2116 if (t == MONO_TYPE_CHAR && string_encoding != MONO_NATIVE_LPWSTR) {
2117 if (to_object) {
2118 mono_mb_emit_byte (mb, CEE_LDIND_U1);
2119 mono_mb_emit_byte (mb, CEE_STIND_I2);
2120 } else {
2121 mono_mb_emit_byte (mb, CEE_LDIND_U2);
2122 mono_mb_emit_byte (mb, CEE_STIND_I1);
2123 }
2124 usize = 1;
2125 } else {
2126 mono_mb_emit_byte (mb, mono_type_to_ldind (etype));
2127 mono_mb_emit_byte (mb, mono_type_to_stind (etype));
2128 }
2129 break;
2130 default:
2131 g_assert_not_reached ();
2132 break;
2133 }
2134
2135 if (to_object) {
2136 mono_mb_emit_add_to_local (mb, 0, usize);
2137 mono_mb_emit_add_to_local (mb, 1, msize);
2138 } else {
2139 mono_mb_emit_add_to_local (mb, 0, msize);
2140 mono_mb_emit_add_to_local (mb, 1, usize);
2141 }
2142
2143 /* Loop footer */
2144 mono_mb_emit_add_to_local (mb, index_var, 1);
2145
2146 mono_mb_emit_branch_label (mb, CEE_BR, label2);
2147
2148 mono_mb_patch_branch (mb, label3);
2149 }
2150
2151 *out_usize = usize * len;
2152 }
2153
2154 static void
emit_struct_conv_full(MonoMethodBuilder * mb,MonoClass * klass,gboolean to_object,int offset_of_first_child_field,MonoMarshalNative string_encoding)2155 emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object,
2156 int offset_of_first_child_field, MonoMarshalNative string_encoding)
2157 {
2158 MonoMarshalType *info;
2159 int i;
2160
2161 if (klass->parent)
2162 emit_struct_conv_full (mb, klass->parent, to_object, offset_of_first_nonstatic_field (klass), string_encoding);
2163
2164 info = mono_marshal_load_type_info (klass);
2165
2166 if (info->native_size == 0)
2167 return;
2168
2169 if (klass->blittable) {
2170 int usize = mono_class_value_size (klass, NULL);
2171 g_assert (usize == info->native_size);
2172 mono_mb_emit_ldloc (mb, 1);
2173 mono_mb_emit_ldloc (mb, 0);
2174 mono_mb_emit_icon (mb, usize);
2175 mono_mb_emit_byte (mb, CEE_PREFIX1);
2176 mono_mb_emit_byte (mb, CEE_CPBLK);
2177
2178 if (to_object) {
2179 mono_mb_emit_add_to_local (mb, 0, usize);
2180 mono_mb_emit_add_to_local (mb, 1, offset_of_first_child_field);
2181 } else {
2182 mono_mb_emit_add_to_local (mb, 0, offset_of_first_child_field);
2183 mono_mb_emit_add_to_local (mb, 1, usize);
2184 }
2185 return;
2186 }
2187
2188 if (klass != mono_class_try_get_safehandle_class ()) {
2189 if (mono_class_is_auto_layout (klass)) {
2190 char *msg = g_strdup_printf ("Type %s which is passed to unmanaged code must have a StructLayout attribute.",
2191 mono_type_full_name (&klass->byval_arg));
2192 mono_mb_emit_exception_marshal_directive (mb, msg);
2193 return;
2194 }
2195 }
2196
2197 for (i = 0; i < info->num_fields; i++) {
2198 MonoMarshalNative ntype;
2199 MonoMarshalConv conv;
2200 MonoType *ftype = info->fields [i].field->type;
2201 int msize = 0;
2202 int usize = 0;
2203 gboolean last_field = i < (info->num_fields -1) ? 0 : 1;
2204
2205 if (ftype->attrs & FIELD_ATTRIBUTE_STATIC)
2206 continue;
2207
2208 ntype = (MonoMarshalNative)mono_type_to_unmanaged (ftype, info->fields [i].mspec, TRUE, klass->unicode, &conv);
2209
2210 if (last_field) {
2211 msize = klass->instance_size - info->fields [i].field->offset;
2212 usize = info->native_size - info->fields [i].offset;
2213 } else {
2214 msize = info->fields [i + 1].field->offset - info->fields [i].field->offset;
2215 usize = info->fields [i + 1].offset - info->fields [i].offset;
2216 }
2217
2218 if (klass != mono_class_try_get_safehandle_class ()){
2219 /*
2220 * FIXME: Should really check for usize==0 and msize>0, but we apply
2221 * the layout to the managed structure as well.
2222 */
2223
2224 if (mono_class_is_explicit_layout (klass) && (usize == 0)) {
2225 if (MONO_TYPE_IS_REFERENCE (info->fields [i].field->type) ||
2226 ((!last_field && MONO_TYPE_IS_REFERENCE (info->fields [i + 1].field->type))))
2227 g_error ("Type %s which has an [ExplicitLayout] attribute cannot have a "
2228 "reference field at the same offset as another field.",
2229 mono_type_full_name (&klass->byval_arg));
2230 }
2231 }
2232
2233 switch (conv) {
2234 case MONO_MARSHAL_CONV_NONE: {
2235 int t;
2236
2237 //XXX a byref field!?!? that's not allowed! and worse, it might miss a WB
2238 g_assert (!ftype->byref);
2239 if (ftype->type == MONO_TYPE_I || ftype->type == MONO_TYPE_U) {
2240 mono_mb_emit_ldloc (mb, 1);
2241 mono_mb_emit_ldloc (mb, 0);
2242 mono_mb_emit_byte (mb, CEE_LDIND_I);
2243 mono_mb_emit_byte (mb, CEE_STIND_I);
2244 break;
2245 }
2246
2247 handle_enum:
2248 t = ftype->type;
2249 switch (t) {
2250 case MONO_TYPE_I4:
2251 case MONO_TYPE_U4:
2252 case MONO_TYPE_I1:
2253 case MONO_TYPE_U1:
2254 case MONO_TYPE_BOOLEAN:
2255 case MONO_TYPE_I2:
2256 case MONO_TYPE_U2:
2257 case MONO_TYPE_CHAR:
2258 case MONO_TYPE_I8:
2259 case MONO_TYPE_U8:
2260 case MONO_TYPE_PTR:
2261 case MONO_TYPE_R4:
2262 case MONO_TYPE_R8:
2263 mono_mb_emit_ldloc (mb, 1);
2264 mono_mb_emit_ldloc (mb, 0);
2265 if (t == MONO_TYPE_CHAR && ntype == MONO_NATIVE_U1 && string_encoding != MONO_NATIVE_LPWSTR) {
2266 if (to_object) {
2267 mono_mb_emit_byte (mb, CEE_LDIND_U1);
2268 mono_mb_emit_byte (mb, CEE_STIND_I2);
2269 } else {
2270 mono_mb_emit_byte (mb, CEE_LDIND_U2);
2271 mono_mb_emit_byte (mb, CEE_STIND_I1);
2272 }
2273 } else {
2274 mono_mb_emit_byte (mb, mono_type_to_ldind (ftype));
2275 mono_mb_emit_byte (mb, mono_type_to_stind (ftype));
2276 }
2277 break;
2278 case MONO_TYPE_VALUETYPE: {
2279 int src_var, dst_var;
2280 MonoType *etype;
2281 int len;
2282
2283 if (ftype->data.klass->enumtype) {
2284 ftype = mono_class_enum_basetype (ftype->data.klass);
2285 goto handle_enum;
2286 }
2287
2288 src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2289 dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2290
2291 /* save the old src pointer */
2292 mono_mb_emit_ldloc (mb, 0);
2293 mono_mb_emit_stloc (mb, src_var);
2294 /* save the old dst pointer */
2295 mono_mb_emit_ldloc (mb, 1);
2296 mono_mb_emit_stloc (mb, dst_var);
2297
2298 if (get_fixed_buffer_attr (info->fields [i].field, &etype, &len)) {
2299 emit_fixed_buf_conv (mb, ftype, etype, len, to_object, &usize);
2300 } else {
2301 emit_struct_conv (mb, ftype->data.klass, to_object);
2302 }
2303
2304 /* restore the old src pointer */
2305 mono_mb_emit_ldloc (mb, src_var);
2306 mono_mb_emit_stloc (mb, 0);
2307 /* restore the old dst pointer */
2308 mono_mb_emit_ldloc (mb, dst_var);
2309 mono_mb_emit_stloc (mb, 1);
2310 break;
2311 }
2312 case MONO_TYPE_OBJECT: {
2313 #ifndef DISABLE_COM
2314 if (to_object) {
2315 static MonoMethod *variant_clear = NULL;
2316 static MonoMethod *get_object_for_native_variant = NULL;
2317
2318 if (!variant_clear)
2319 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
2320 if (!get_object_for_native_variant)
2321 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
2322 mono_mb_emit_ldloc (mb, 1);
2323 mono_mb_emit_ldloc (mb, 0);
2324 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
2325 mono_mb_emit_byte (mb, CEE_STIND_REF);
2326
2327 mono_mb_emit_ldloc (mb, 0);
2328 mono_mb_emit_managed_call (mb, variant_clear, NULL);
2329 }
2330 else {
2331 static MonoMethod *get_native_variant_for_object = NULL;
2332
2333 if (!get_native_variant_for_object)
2334 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
2335
2336 mono_mb_emit_ldloc (mb, 0);
2337 mono_mb_emit_byte(mb, CEE_LDIND_REF);
2338 mono_mb_emit_ldloc (mb, 1);
2339 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
2340 }
2341 #else
2342 char *msg = g_strdup_printf ("COM support was disabled at compilation time.");
2343 mono_mb_emit_exception_marshal_directive (mb, msg);
2344 #endif
2345 break;
2346 }
2347
2348 default:
2349 g_warning ("marshaling type %02x not implemented", ftype->type);
2350 g_assert_not_reached ();
2351 }
2352 break;
2353 }
2354 default: {
2355 int src_var, dst_var;
2356
2357 src_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2358 dst_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2359
2360 /* save the old src pointer */
2361 mono_mb_emit_ldloc (mb, 0);
2362 mono_mb_emit_stloc (mb, src_var);
2363 /* save the old dst pointer */
2364 mono_mb_emit_ldloc (mb, 1);
2365 mono_mb_emit_stloc (mb, dst_var);
2366
2367 if (to_object)
2368 emit_ptr_to_object_conv (mb, ftype, conv, info->fields [i].mspec);
2369 else
2370 emit_object_to_ptr_conv (mb, ftype, conv, info->fields [i].mspec);
2371
2372 /* restore the old src pointer */
2373 mono_mb_emit_ldloc (mb, src_var);
2374 mono_mb_emit_stloc (mb, 0);
2375 /* restore the old dst pointer */
2376 mono_mb_emit_ldloc (mb, dst_var);
2377 mono_mb_emit_stloc (mb, 1);
2378 }
2379 }
2380
2381 if (to_object) {
2382 mono_mb_emit_add_to_local (mb, 0, usize);
2383 mono_mb_emit_add_to_local (mb, 1, msize);
2384 } else {
2385 mono_mb_emit_add_to_local (mb, 0, msize);
2386 mono_mb_emit_add_to_local (mb, 1, usize);
2387 }
2388 }
2389 }
2390
2391 static void
emit_struct_conv(MonoMethodBuilder * mb,MonoClass * klass,gboolean to_object)2392 emit_struct_conv (MonoMethodBuilder *mb, MonoClass *klass, gboolean to_object)
2393 {
2394 emit_struct_conv_full (mb, klass, to_object, 0, (MonoMarshalNative)-1);
2395 }
2396
2397 static void
emit_struct_free(MonoMethodBuilder * mb,MonoClass * klass,int struct_var)2398 emit_struct_free (MonoMethodBuilder *mb, MonoClass *klass, int struct_var)
2399 {
2400 /* Call DestroyStructure */
2401 /* FIXME: Only do this if needed */
2402 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
2403 mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
2404 mono_mb_emit_ldloc (mb, struct_var);
2405 mono_mb_emit_icall (mb, mono_struct_delete_old);
2406 }
2407
2408 static void
emit_thread_interrupt_checkpoint_call(MonoMethodBuilder * mb,gpointer checkpoint_func)2409 emit_thread_interrupt_checkpoint_call (MonoMethodBuilder *mb, gpointer checkpoint_func)
2410 {
2411 int pos_noabort, pos_noex;
2412
2413 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
2414 mono_mb_emit_byte (mb, CEE_MONO_LDPTR_INT_REQ_FLAG);
2415 mono_mb_emit_byte (mb, CEE_LDIND_U4);
2416 pos_noabort = mono_mb_emit_branch (mb, CEE_BRFALSE);
2417
2418 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
2419 mono_mb_emit_byte (mb, CEE_MONO_NOT_TAKEN);
2420
2421 mono_mb_emit_icall (mb, checkpoint_func);
2422 /* Throw the exception returned by the checkpoint function, if any */
2423 mono_mb_emit_byte (mb, CEE_DUP);
2424 pos_noex = mono_mb_emit_branch (mb, CEE_BRFALSE);
2425 mono_mb_emit_byte (mb, CEE_THROW);
2426 mono_mb_patch_branch (mb, pos_noex);
2427 mono_mb_emit_byte (mb, CEE_POP);
2428
2429 mono_mb_patch_branch (mb, pos_noabort);
2430 }
2431
2432 static void
emit_thread_interrupt_checkpoint(MonoMethodBuilder * mb)2433 emit_thread_interrupt_checkpoint (MonoMethodBuilder *mb)
2434 {
2435 if (strstr (mb->name, "mono_thread_interruption_checkpoint"))
2436 return;
2437
2438 emit_thread_interrupt_checkpoint_call (mb, mono_thread_interruption_checkpoint);
2439 }
2440
2441 static void
emit_thread_force_interrupt_checkpoint(MonoMethodBuilder * mb)2442 emit_thread_force_interrupt_checkpoint (MonoMethodBuilder *mb)
2443 {
2444 emit_thread_interrupt_checkpoint_call (mb, mono_thread_force_interruption_checkpoint_noraise);
2445 }
2446
2447 void
mono_marshal_emit_thread_interrupt_checkpoint(MonoMethodBuilder * mb)2448 mono_marshal_emit_thread_interrupt_checkpoint (MonoMethodBuilder *mb)
2449 {
2450 emit_thread_interrupt_checkpoint (mb);
2451 }
2452
2453 void
mono_marshal_emit_thread_force_interrupt_checkpoint(MonoMethodBuilder * mb)2454 mono_marshal_emit_thread_force_interrupt_checkpoint (MonoMethodBuilder *mb)
2455 {
2456 emit_thread_force_interrupt_checkpoint (mb);
2457 }
2458
2459 #endif /* ENABLE_ILGEN */
2460
2461 /* This is a JIT icall, it sets the pending exception and returns NULL on error. */
2462 static MonoAsyncResult *
mono_delegate_begin_invoke(MonoDelegate * delegate,gpointer * params)2463 mono_delegate_begin_invoke (MonoDelegate *delegate, gpointer *params)
2464 {
2465 MonoError error;
2466 MonoMulticastDelegate *mcast_delegate;
2467 MonoClass *klass;
2468 MonoMethod *method;
2469
2470 g_assert (delegate);
2471 mcast_delegate = (MonoMulticastDelegate *) delegate;
2472 if (mcast_delegate->delegates != NULL) {
2473 mono_set_pending_exception (mono_get_exception_argument (NULL, "The delegate must have only one target"));
2474 return NULL;
2475 }
2476
2477 #ifndef DISABLE_REMOTING
2478 if (delegate->target && mono_object_is_transparent_proxy (delegate->target)) {
2479 MonoTransparentProxy* tp = (MonoTransparentProxy *)delegate->target;
2480 if (!mono_class_is_contextbound (tp->remote_class->proxy_class) || tp->rp->context != (MonoObject *) mono_context_get ()) {
2481 /* If the target is a proxy, make a direct call. Is proxy's work
2482 // to make the call asynchronous.
2483 */
2484 MonoMethodMessage *msg;
2485 MonoDelegate *async_callback;
2486 MonoObject *state;
2487 MonoAsyncResult *ares;
2488 MonoObject *exc;
2489 MonoArray *out_args;
2490 method = delegate->method;
2491
2492 msg = mono_method_call_message_new (mono_marshal_method_from_wrapper (method), params, NULL, &async_callback, &state, &error);
2493 if (mono_error_set_pending_exception (&error))
2494 return NULL;
2495 ares = mono_async_result_new (mono_domain_get (), NULL, state, NULL, NULL, &error);
2496 if (mono_error_set_pending_exception (&error))
2497 return NULL;
2498 MONO_OBJECT_SETREF (ares, async_delegate, (MonoObject *)delegate);
2499 MONO_OBJECT_SETREF (ares, async_callback, (MonoObject *)async_callback);
2500 MONO_OBJECT_SETREF (msg, async_result, ares);
2501 msg->call_type = CallType_BeginInvoke;
2502
2503 exc = NULL;
2504 mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args, &error);
2505 if (!mono_error_ok (&error)) {
2506 mono_error_set_pending_exception (&error);
2507 return NULL;
2508 }
2509 if (exc)
2510 mono_set_pending_exception ((MonoException *) exc);
2511 return ares;
2512 }
2513 }
2514 #endif
2515
2516 klass = delegate->object.vtable->klass;
2517
2518 method = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
2519 if (!method)
2520 method = mono_get_delegate_invoke (klass);
2521 g_assert (method);
2522
2523 MonoAsyncResult *result = mono_threadpool_begin_invoke (mono_domain_get (), (MonoObject*) delegate, method, params, &error);
2524 mono_error_set_pending_exception (&error);
2525 return result;
2526 }
2527
2528 #ifdef ENABLE_ILGEN
2529
2530 int
mono_mb_emit_save_args(MonoMethodBuilder * mb,MonoMethodSignature * sig,gboolean save_this)2531 mono_mb_emit_save_args (MonoMethodBuilder *mb, MonoMethodSignature *sig, gboolean save_this)
2532 {
2533 int i, params_var, tmp_var;
2534
2535 /* allocate local (pointer) *params[] */
2536 params_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2537 /* allocate local (pointer) tmp */
2538 tmp_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
2539
2540 /* alloate space on stack to store an array of pointers to the arguments */
2541 mono_mb_emit_icon (mb, sizeof (gpointer) * (sig->param_count + 1));
2542 mono_mb_emit_byte (mb, CEE_PREFIX1);
2543 mono_mb_emit_byte (mb, CEE_LOCALLOC);
2544 mono_mb_emit_stloc (mb, params_var);
2545
2546 /* tmp = params */
2547 mono_mb_emit_ldloc (mb, params_var);
2548 mono_mb_emit_stloc (mb, tmp_var);
2549
2550 if (save_this && sig->hasthis) {
2551 mono_mb_emit_ldloc (mb, tmp_var);
2552 mono_mb_emit_ldarg_addr (mb, 0);
2553 mono_mb_emit_byte (mb, CEE_STIND_I);
2554 /* tmp = tmp + sizeof (gpointer) */
2555 if (sig->param_count)
2556 mono_mb_emit_add_to_local (mb, tmp_var, sizeof (gpointer));
2557
2558 }
2559
2560 for (i = 0; i < sig->param_count; i++) {
2561 mono_mb_emit_ldloc (mb, tmp_var);
2562 mono_mb_emit_ldarg_addr (mb, i + sig->hasthis);
2563 mono_mb_emit_byte (mb, CEE_STIND_I);
2564 /* tmp = tmp + sizeof (gpointer) */
2565 if (i < (sig->param_count - 1))
2566 mono_mb_emit_add_to_local (mb, tmp_var, sizeof (gpointer));
2567 }
2568
2569 return params_var;
2570 }
2571
2572 #endif /* ENABLE_ILGEN */
2573
2574 static char*
mono_signature_to_name(MonoMethodSignature * sig,const char * prefix)2575 mono_signature_to_name (MonoMethodSignature *sig, const char *prefix)
2576 {
2577 int i;
2578 char *result;
2579 GString *res = g_string_new ("");
2580
2581 if (prefix) {
2582 g_string_append (res, prefix);
2583 g_string_append_c (res, '_');
2584 }
2585
2586 mono_type_get_desc (res, sig->ret, FALSE);
2587
2588 if (sig->hasthis)
2589 g_string_append (res, "__this__");
2590
2591 for (i = 0; i < sig->param_count; ++i) {
2592 g_string_append_c (res, '_');
2593 mono_type_get_desc (res, sig->params [i], FALSE);
2594 }
2595 result = res->str;
2596 g_string_free (res, FALSE);
2597 return result;
2598 }
2599
2600 /**
2601 * mono_marshal_get_string_encoding:
2602 *
2603 * Return the string encoding which should be used for a given parameter.
2604 */
2605 static MonoMarshalNative
mono_marshal_get_string_encoding(MonoMethodPInvoke * piinfo,MonoMarshalSpec * spec)2606 mono_marshal_get_string_encoding (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec)
2607 {
2608 /* First try the parameter marshal info */
2609 if (spec) {
2610 if (spec->native == MONO_NATIVE_LPARRAY) {
2611 if ((spec->data.array_data.elem_type != 0) && (spec->data.array_data.elem_type != MONO_NATIVE_MAX))
2612 return spec->data.array_data.elem_type;
2613 }
2614 else
2615 return spec->native;
2616 }
2617
2618 if (!piinfo)
2619 return MONO_NATIVE_LPSTR;
2620
2621 /* Then try the method level marshal info */
2622 switch (piinfo->piflags & PINVOKE_ATTRIBUTE_CHAR_SET_MASK) {
2623 case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI:
2624 return MONO_NATIVE_LPSTR;
2625 case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE:
2626 return MONO_NATIVE_LPWSTR;
2627 case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO:
2628 #ifdef TARGET_WIN32
2629 return MONO_NATIVE_LPWSTR;
2630 #else
2631 return MONO_NATIVE_LPSTR;
2632 #endif
2633 default:
2634 return MONO_NATIVE_LPSTR;
2635 }
2636 }
2637
2638 static MonoMarshalConv
mono_marshal_get_string_to_ptr_conv(MonoMethodPInvoke * piinfo,MonoMarshalSpec * spec)2639 mono_marshal_get_string_to_ptr_conv (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec)
2640 {
2641 MonoMarshalNative encoding = mono_marshal_get_string_encoding (piinfo, spec);
2642
2643 switch (encoding) {
2644 case MONO_NATIVE_LPWSTR:
2645 return MONO_MARSHAL_CONV_STR_LPWSTR;
2646 case MONO_NATIVE_LPSTR:
2647 case MONO_NATIVE_VBBYREFSTR:
2648 return MONO_MARSHAL_CONV_STR_LPSTR;
2649 case MONO_NATIVE_LPTSTR:
2650 return MONO_MARSHAL_CONV_STR_LPTSTR;
2651 case MONO_NATIVE_BSTR:
2652 return MONO_MARSHAL_CONV_STR_BSTR;
2653 case MONO_NATIVE_UTF8STR:
2654 return MONO_MARSHAL_CONV_STR_UTF8STR;
2655 default:
2656 return MONO_MARSHAL_CONV_INVALID;
2657 }
2658 }
2659
2660 static MonoMarshalConv
mono_marshal_get_stringbuilder_to_ptr_conv(MonoMethodPInvoke * piinfo,MonoMarshalSpec * spec)2661 mono_marshal_get_stringbuilder_to_ptr_conv (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec)
2662 {
2663 MonoMarshalNative encoding = mono_marshal_get_string_encoding (piinfo, spec);
2664
2665 switch (encoding) {
2666 case MONO_NATIVE_LPWSTR:
2667 return MONO_MARSHAL_CONV_SB_LPWSTR;
2668 case MONO_NATIVE_LPSTR:
2669 return MONO_MARSHAL_CONV_SB_LPSTR;
2670 case MONO_NATIVE_UTF8STR:
2671 return MONO_MARSHAL_CONV_SB_UTF8STR;
2672 case MONO_NATIVE_LPTSTR:
2673 return MONO_MARSHAL_CONV_SB_LPTSTR;
2674 default:
2675 return MONO_MARSHAL_CONV_INVALID;
2676 }
2677 }
2678
2679 static MonoMarshalConv
mono_marshal_get_ptr_to_string_conv(MonoMethodPInvoke * piinfo,MonoMarshalSpec * spec,gboolean * need_free)2680 mono_marshal_get_ptr_to_string_conv (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec, gboolean *need_free)
2681 {
2682 MonoMarshalNative encoding = mono_marshal_get_string_encoding (piinfo, spec);
2683
2684 *need_free = TRUE;
2685
2686 switch (encoding) {
2687 case MONO_NATIVE_LPWSTR:
2688 *need_free = FALSE;
2689 return MONO_MARSHAL_CONV_LPWSTR_STR;
2690 case MONO_NATIVE_UTF8STR:
2691 return MONO_MARSHAL_CONV_UTF8STR_STR;
2692 case MONO_NATIVE_LPSTR:
2693 case MONO_NATIVE_VBBYREFSTR:
2694 return MONO_MARSHAL_CONV_LPSTR_STR;
2695 case MONO_NATIVE_LPTSTR:
2696 #ifdef TARGET_WIN32
2697 *need_free = FALSE;
2698 #endif
2699 return MONO_MARSHAL_CONV_LPTSTR_STR;
2700 case MONO_NATIVE_BSTR:
2701 return MONO_MARSHAL_CONV_BSTR_STR;
2702 default:
2703 return MONO_MARSHAL_CONV_INVALID;
2704 }
2705 }
2706
2707 static MonoMarshalConv
mono_marshal_get_ptr_to_stringbuilder_conv(MonoMethodPInvoke * piinfo,MonoMarshalSpec * spec,gboolean * need_free)2708 mono_marshal_get_ptr_to_stringbuilder_conv (MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec, gboolean *need_free)
2709 {
2710 MonoMarshalNative encoding = mono_marshal_get_string_encoding (piinfo, spec);
2711
2712 *need_free = TRUE;
2713
2714 switch (encoding) {
2715 case MONO_NATIVE_LPWSTR:
2716 /*
2717 * mono_string_builder_to_utf16 does not allocate a
2718 * new buffer, so no need to free it.
2719 */
2720 *need_free = FALSE;
2721 return MONO_MARSHAL_CONV_LPWSTR_SB;
2722 case MONO_NATIVE_UTF8STR:
2723 return MONO_MARSHAL_CONV_UTF8STR_SB;
2724 case MONO_NATIVE_LPSTR:
2725 return MONO_MARSHAL_CONV_LPSTR_SB;
2726 break;
2727 case MONO_NATIVE_LPTSTR:
2728 return MONO_MARSHAL_CONV_LPTSTR_SB;
2729 break;
2730 default:
2731 return MONO_MARSHAL_CONV_INVALID;
2732 }
2733 }
2734
2735 /*
2736 * Return whenever a field of a native structure or an array member needs to
2737 * be freed.
2738 */
2739 static gboolean
mono_marshal_need_free(MonoType * t,MonoMethodPInvoke * piinfo,MonoMarshalSpec * spec)2740 mono_marshal_need_free (MonoType *t, MonoMethodPInvoke *piinfo, MonoMarshalSpec *spec)
2741 {
2742 MonoMarshalNative encoding;
2743
2744 switch (t->type) {
2745 case MONO_TYPE_VALUETYPE:
2746 /* FIXME: Optimize this */
2747 return TRUE;
2748 case MONO_TYPE_OBJECT:
2749 case MONO_TYPE_CLASS:
2750 if (t->data.klass == mono_defaults.stringbuilder_class) {
2751 gboolean need_free;
2752 mono_marshal_get_ptr_to_stringbuilder_conv (piinfo, spec, &need_free);
2753 return need_free;
2754 }
2755 return FALSE;
2756 case MONO_TYPE_STRING:
2757 encoding = mono_marshal_get_string_encoding (piinfo, spec);
2758 return (encoding == MONO_NATIVE_LPWSTR) ? FALSE : TRUE;
2759 default:
2760 return FALSE;
2761 }
2762 }
2763
2764 /*
2765 * Return the hash table pointed to by VAR, lazily creating it if neccesary.
2766 */
2767 static GHashTable*
get_cache(GHashTable ** var,GHashFunc hash_func,GCompareFunc equal_func)2768 get_cache (GHashTable **var, GHashFunc hash_func, GCompareFunc equal_func)
2769 {
2770 if (!(*var)) {
2771 mono_marshal_lock ();
2772 if (!(*var)) {
2773 GHashTable *cache =
2774 g_hash_table_new (hash_func, equal_func);
2775 mono_memory_barrier ();
2776 *var = cache;
2777 }
2778 mono_marshal_unlock ();
2779 }
2780 return *var;
2781 }
2782
2783 GHashTable*
mono_marshal_get_cache(GHashTable ** var,GHashFunc hash_func,GCompareFunc equal_func)2784 mono_marshal_get_cache (GHashTable **var, GHashFunc hash_func, GCompareFunc equal_func)
2785 {
2786 return get_cache (var, hash_func, equal_func);
2787 }
2788
2789 MonoMethod*
mono_marshal_find_in_cache(GHashTable * cache,gpointer key)2790 mono_marshal_find_in_cache (GHashTable *cache, gpointer key)
2791 {
2792 MonoMethod *res;
2793
2794 mono_marshal_lock ();
2795 res = (MonoMethod *)g_hash_table_lookup (cache, key);
2796 mono_marshal_unlock ();
2797 return res;
2798 }
2799
2800 /*
2801 * mono_mb_create:
2802 *
2803 * Create a MonoMethod from MB, set INFO as wrapper info.
2804 */
2805 MonoMethod*
mono_mb_create(MonoMethodBuilder * mb,MonoMethodSignature * sig,int max_stack,WrapperInfo * info)2806 mono_mb_create (MonoMethodBuilder *mb, MonoMethodSignature *sig,
2807 int max_stack, WrapperInfo *info)
2808 {
2809 MonoMethod *res;
2810
2811 res = mono_mb_create_method (mb, sig, max_stack);
2812 if (info)
2813 mono_marshal_set_wrapper_info (res, info);
2814 return res;
2815 }
2816
2817 /* Create the method from the builder and place it in the cache */
2818 MonoMethod*
mono_mb_create_and_cache_full(GHashTable * cache,gpointer key,MonoMethodBuilder * mb,MonoMethodSignature * sig,int max_stack,WrapperInfo * info,gboolean * out_found)2819 mono_mb_create_and_cache_full (GHashTable *cache, gpointer key,
2820 MonoMethodBuilder *mb, MonoMethodSignature *sig,
2821 int max_stack, WrapperInfo *info, gboolean *out_found)
2822 {
2823 MonoMethod *res;
2824
2825 if (out_found)
2826 *out_found = FALSE;
2827
2828 mono_marshal_lock ();
2829 res = (MonoMethod *)g_hash_table_lookup (cache, key);
2830 mono_marshal_unlock ();
2831 if (!res) {
2832 MonoMethod *newm;
2833 newm = mono_mb_create_method (mb, sig, max_stack);
2834 mono_marshal_lock ();
2835 res = (MonoMethod *)g_hash_table_lookup (cache, key);
2836 if (!res) {
2837 res = newm;
2838 g_hash_table_insert (cache, key, res);
2839 mono_marshal_set_wrapper_info (res, info);
2840 mono_marshal_unlock ();
2841 } else {
2842 if (out_found)
2843 *out_found = TRUE;
2844 mono_marshal_unlock ();
2845 mono_free_method (newm);
2846 }
2847 }
2848
2849 return res;
2850 }
2851
2852 MonoMethod*
mono_mb_create_and_cache(GHashTable * cache,gpointer key,MonoMethodBuilder * mb,MonoMethodSignature * sig,int max_stack)2853 mono_mb_create_and_cache (GHashTable *cache, gpointer key,
2854 MonoMethodBuilder *mb, MonoMethodSignature *sig,
2855 int max_stack)
2856 {
2857 return mono_mb_create_and_cache_full (cache, key, mb, sig, max_stack, NULL, NULL);
2858 }
2859
2860 /**
2861 * mono_marshal_method_from_wrapper:
2862 */
2863 MonoMethod *
mono_marshal_method_from_wrapper(MonoMethod * wrapper)2864 mono_marshal_method_from_wrapper (MonoMethod *wrapper)
2865 {
2866 MonoMethod *m;
2867 int wrapper_type = wrapper->wrapper_type;
2868 WrapperInfo *info;
2869
2870 if (wrapper_type == MONO_WRAPPER_NONE || wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
2871 return wrapper;
2872
2873 info = mono_marshal_get_wrapper_info (wrapper);
2874
2875 switch (wrapper_type) {
2876 case MONO_WRAPPER_REMOTING_INVOKE:
2877 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
2878 case MONO_WRAPPER_XDOMAIN_INVOKE:
2879 m = info->d.remoting.method;
2880 if (wrapper->is_inflated) {
2881 MonoError error;
2882 MonoMethod *result;
2883 /*
2884 * A method cannot be inflated and a wrapper at the same time, so the wrapper info
2885 * contains an uninflated method.
2886 */
2887 result = mono_class_inflate_generic_method_checked (m, mono_method_get_context (wrapper), &error);
2888 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2889 return result;
2890 }
2891 return m;
2892 case MONO_WRAPPER_SYNCHRONIZED:
2893 m = info->d.synchronized.method;
2894 if (wrapper->is_inflated) {
2895 MonoError error;
2896 MonoMethod *result;
2897 result = mono_class_inflate_generic_method_checked (m, mono_method_get_context (wrapper), &error);
2898 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2899 return result;
2900 }
2901 return m;
2902 case MONO_WRAPPER_UNBOX:
2903 return info->d.unbox.method;
2904 case MONO_WRAPPER_MANAGED_TO_NATIVE:
2905 if (info && (info->subtype == WRAPPER_SUBTYPE_NONE || info->subtype == WRAPPER_SUBTYPE_NATIVE_FUNC_AOT || info->subtype == WRAPPER_SUBTYPE_PINVOKE))
2906 return info->d.managed_to_native.method;
2907 else
2908 return NULL;
2909 case MONO_WRAPPER_RUNTIME_INVOKE:
2910 if (info && (info->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT || info->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL))
2911 return info->d.runtime_invoke.method;
2912 else
2913 return NULL;
2914 case MONO_WRAPPER_DELEGATE_INVOKE:
2915 if (info)
2916 return info->d.delegate_invoke.method;
2917 else
2918 return NULL;
2919 default:
2920 return NULL;
2921 }
2922 }
2923
2924 /*
2925 * mono_marshal_get_wrapper_info:
2926 *
2927 * Retrieve the WrapperInfo structure associated with WRAPPER.
2928 */
2929 WrapperInfo*
mono_marshal_get_wrapper_info(MonoMethod * wrapper)2930 mono_marshal_get_wrapper_info (MonoMethod *wrapper)
2931 {
2932 g_assert (wrapper->wrapper_type);
2933
2934 return (WrapperInfo *)mono_method_get_wrapper_data (wrapper, 1);
2935 }
2936
2937 /*
2938 * mono_marshal_set_wrapper_info:
2939 *
2940 * Set the WrapperInfo structure associated with the wrapper
2941 * method METHOD to INFO.
2942 */
2943 void
mono_marshal_set_wrapper_info(MonoMethod * method,WrapperInfo * info)2944 mono_marshal_set_wrapper_info (MonoMethod *method, WrapperInfo *info)
2945 {
2946 void **datav;
2947 /* assert */
2948 if (method->wrapper_type == MONO_WRAPPER_NONE || method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
2949 return;
2950
2951 datav = (void **)((MonoMethodWrapper *)method)->method_data;
2952 datav [1] = info;
2953 }
2954
2955 WrapperInfo*
mono_wrapper_info_create(MonoMethodBuilder * mb,WrapperSubtype subtype)2956 mono_wrapper_info_create (MonoMethodBuilder *mb, WrapperSubtype subtype)
2957 {
2958 WrapperInfo *info;
2959
2960 info = (WrapperInfo *)mono_image_alloc0 (mb->method->klass->image, sizeof (WrapperInfo));
2961 info->subtype = subtype;
2962 return info;
2963 }
2964
2965 /*
2966 * get_wrapper_target_class:
2967 *
2968 * Return the class where a wrapper method should be placed.
2969 */
2970 static MonoClass*
get_wrapper_target_class(MonoImage * image)2971 get_wrapper_target_class (MonoImage *image)
2972 {
2973 MonoError error;
2974 MonoClass *klass;
2975
2976 /*
2977 * Notes:
2978 * - can't put all wrappers into an mscorlib class, because they reference
2979 * metadata (signature) so they should be put into the same image as the
2980 * method they wrap, so they are unloaded together.
2981 * - putting them into a class with a type initalizer could cause the
2982 * initializer to be executed which can be a problem if the wrappers are
2983 * shared.
2984 * - putting them into an inflated class can cause problems if the the
2985 * class is deleted because it references an image which is unloaded.
2986 * To avoid these problems, we put the wrappers into the <Module> class of
2987 * the image.
2988 */
2989 if (image_is_dynamic (image)) {
2990 klass = ((MonoDynamicImage*)image)->wrappers_type;
2991 } else {
2992 klass = mono_class_get_checked (image, mono_metadata_make_token (MONO_TABLE_TYPEDEF, 1), &error);
2993 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
2994 }
2995 g_assert (klass);
2996
2997 return klass;
2998 }
2999
3000 /*
3001 * Wrappers for generic methods should be instances of generic wrapper methods, i.e .the wrapper for Sort<int> should be
3002 * an instance of the wrapper for Sort<T>. This is required for full-aot to work.
3003 */
3004
3005 /*
3006 * check_generic_wrapper_cache:
3007 *
3008 * Check CACHE for the wrapper of the generic instance ORIG_METHOD, and return it if it is found.
3009 * KEY should be the key for ORIG_METHOD in the cache, while DEF_KEY should be the key of its
3010 * generic method definition.
3011 */
3012 static MonoMethod*
check_generic_wrapper_cache(GHashTable * cache,MonoMethod * orig_method,gpointer key,gpointer def_key)3013 check_generic_wrapper_cache (GHashTable *cache, MonoMethod *orig_method, gpointer key, gpointer def_key)
3014 {
3015 MonoMethod *res;
3016 MonoMethod *inst, *def;
3017 MonoGenericContext *ctx;
3018
3019 g_assert (orig_method->is_inflated);
3020 ctx = mono_method_get_context (orig_method);
3021
3022 /*
3023 * Look for the instance
3024 */
3025 res = mono_marshal_find_in_cache (cache, key);
3026 if (res)
3027 return res;
3028
3029 /*
3030 * Look for the definition
3031 */
3032 def = mono_marshal_find_in_cache (cache, def_key);
3033 if (def) {
3034 MonoError error;
3035 inst = mono_class_inflate_generic_method_checked (def, ctx, &error);
3036 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3037 /* Cache it */
3038 mono_memory_barrier ();
3039 mono_marshal_lock ();
3040 res = (MonoMethod *)g_hash_table_lookup (cache, key);
3041 if (!res) {
3042 g_hash_table_insert (cache, key, inst);
3043 res = inst;
3044 }
3045 mono_marshal_unlock ();
3046 return res;
3047 }
3048 return NULL;
3049 }
3050
3051 static MonoMethod*
cache_generic_wrapper(GHashTable * cache,MonoMethod * orig_method,MonoMethod * def,MonoGenericContext * ctx,gpointer key)3052 cache_generic_wrapper (GHashTable *cache, MonoMethod *orig_method, MonoMethod *def, MonoGenericContext *ctx, gpointer key)
3053 {
3054 MonoError error;
3055 MonoMethod *inst, *res;
3056
3057 /*
3058 * We use the same cache for the generic definition and the instances.
3059 */
3060 inst = mono_class_inflate_generic_method_checked (def, ctx, &error);
3061 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3062 mono_memory_barrier ();
3063 mono_marshal_lock ();
3064 res = (MonoMethod *)g_hash_table_lookup (cache, key);
3065 if (!res) {
3066 g_hash_table_insert (cache, key, inst);
3067 res = inst;
3068 }
3069 mono_marshal_unlock ();
3070 return res;
3071 }
3072
3073 static MonoMethod*
check_generic_delegate_wrapper_cache(GHashTable * cache,MonoMethod * orig_method,MonoMethod * def_method,MonoGenericContext * ctx)3074 check_generic_delegate_wrapper_cache (GHashTable *cache, MonoMethod *orig_method, MonoMethod *def_method, MonoGenericContext *ctx)
3075 {
3076 MonoError error;
3077 MonoMethod *res;
3078 MonoMethod *inst, *def;
3079
3080 /*
3081 * Look for the instance
3082 */
3083 res = mono_marshal_find_in_cache (cache, orig_method->klass);
3084 if (res)
3085 return res;
3086
3087 /*
3088 * Look for the definition
3089 */
3090 def = mono_marshal_find_in_cache (cache, def_method->klass);
3091 if (def) {
3092 inst = mono_class_inflate_generic_method_checked (def, ctx, &error);
3093 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3094
3095 /* Cache it */
3096 mono_memory_barrier ();
3097 mono_marshal_lock ();
3098 res = (MonoMethod *)g_hash_table_lookup (cache, orig_method->klass);
3099 if (!res) {
3100 g_hash_table_insert (cache, orig_method->klass, inst);
3101 res = inst;
3102 }
3103 mono_marshal_unlock ();
3104 return res;
3105 }
3106 return NULL;
3107 }
3108
3109 static MonoMethod*
cache_generic_delegate_wrapper(GHashTable * cache,MonoMethod * orig_method,MonoMethod * def,MonoGenericContext * ctx)3110 cache_generic_delegate_wrapper (GHashTable *cache, MonoMethod *orig_method, MonoMethod *def, MonoGenericContext *ctx)
3111 {
3112 MonoError error;
3113 MonoMethod *inst, *res;
3114 WrapperInfo *ginfo, *info;
3115
3116 /*
3117 * We use the same cache for the generic definition and the instances.
3118 */
3119 inst = mono_class_inflate_generic_method_checked (def, ctx, &error);
3120 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3121
3122 ginfo = mono_marshal_get_wrapper_info (def);
3123 if (ginfo) {
3124 info = (WrapperInfo *)mono_image_alloc0 (def->klass->image, sizeof (WrapperInfo));
3125 info->subtype = ginfo->subtype;
3126 if (info->subtype == WRAPPER_SUBTYPE_NONE) {
3127 info->d.delegate_invoke.method = mono_class_inflate_generic_method_checked (ginfo->d.delegate_invoke.method, ctx, &error);
3128 mono_error_assert_ok (&error);
3129 }
3130 }
3131
3132 mono_memory_barrier ();
3133 mono_marshal_lock ();
3134 res = (MonoMethod *)g_hash_table_lookup (cache, orig_method->klass);
3135 if (!res) {
3136 g_hash_table_insert (cache, orig_method->klass, inst);
3137 res = inst;
3138 }
3139 mono_marshal_unlock ();
3140 return res;
3141 }
3142
3143 /**
3144 * mono_marshal_get_delegate_begin_invoke:
3145 */
3146 MonoMethod *
mono_marshal_get_delegate_begin_invoke(MonoMethod * method)3147 mono_marshal_get_delegate_begin_invoke (MonoMethod *method)
3148 {
3149 MonoMethodSignature *sig;
3150 MonoMethodBuilder *mb;
3151 MonoMethod *res;
3152 GHashTable *cache;
3153 int params_var;
3154 char *name;
3155 MonoGenericContext *ctx = NULL;
3156 MonoMethod *orig_method = NULL;
3157
3158 g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
3159 !strcmp (method->name, "BeginInvoke"));
3160
3161 /*
3162 * For generic delegates, create a generic wrapper, and returns an instance to help AOT.
3163 */
3164 if (method->is_inflated) {
3165 orig_method = method;
3166 ctx = &((MonoMethodInflated*)method)->context;
3167 method = ((MonoMethodInflated*)method)->declaring;
3168 }
3169
3170 sig = mono_signature_no_pinvoke (method);
3171
3172 /*
3173 * Check cache
3174 */
3175 if (ctx) {
3176 cache = get_cache (&((MonoMethodInflated*)orig_method)->owner->wrapper_caches.delegate_begin_invoke_cache, mono_aligned_addr_hash, NULL);
3177 res = check_generic_delegate_wrapper_cache (cache, orig_method, method, ctx);
3178 if (res)
3179 return res;
3180 } else {
3181 cache = get_cache (&method->klass->image->wrapper_caches.delegate_begin_invoke_cache,
3182 (GHashFunc)mono_signature_hash,
3183 (GCompareFunc)mono_metadata_signature_equal);
3184 if ((res = mono_marshal_find_in_cache (cache, sig)))
3185 return res;
3186 }
3187
3188 g_assert (sig->hasthis);
3189
3190 name = mono_signature_to_name (sig, "begin_invoke");
3191 if (ctx)
3192 mb = mono_mb_new (method->klass, name, MONO_WRAPPER_DELEGATE_BEGIN_INVOKE);
3193 else
3194 mb = mono_mb_new (get_wrapper_target_class (method->klass->image), name, MONO_WRAPPER_DELEGATE_BEGIN_INVOKE);
3195 g_free (name);
3196
3197 #ifdef ENABLE_ILGEN
3198 params_var = mono_mb_emit_save_args (mb, sig, FALSE);
3199
3200 mono_mb_emit_ldarg (mb, 0);
3201 mono_mb_emit_ldloc (mb, params_var);
3202 mono_mb_emit_icall (mb, mono_delegate_begin_invoke);
3203 mono_mb_emit_byte (mb, CEE_RET);
3204 #endif
3205
3206 if (ctx) {
3207 MonoMethod *def;
3208 def = mono_mb_create_and_cache (cache, method->klass, mb, sig, sig->param_count + 16);
3209 res = cache_generic_delegate_wrapper (cache, orig_method, def, ctx);
3210 } else {
3211 res = mono_mb_create_and_cache (cache, sig, mb, sig, sig->param_count + 16);
3212 }
3213
3214 mono_mb_free (mb);
3215 return res;
3216 }
3217
3218 /* This is a JIT icall, it sets the pending exception and returns NULL on error. */
3219 static MonoObject *
mono_delegate_end_invoke(MonoDelegate * delegate,gpointer * params)3220 mono_delegate_end_invoke (MonoDelegate *delegate, gpointer *params)
3221 {
3222 MonoError error;
3223 MonoDomain *domain = mono_domain_get ();
3224 MonoAsyncResult *ares;
3225 MonoMethod *method = NULL;
3226 MonoMethodSignature *sig;
3227 MonoMethodMessage *msg;
3228 MonoObject *res, *exc;
3229 MonoArray *out_args;
3230 MonoClass *klass;
3231
3232 g_assert (delegate);
3233
3234 if (!delegate->method_info) {
3235 g_assert (delegate->method);
3236 MonoReflectionMethod *rm = mono_method_get_object_checked (domain, delegate->method, NULL, &error);
3237 if (!mono_error_ok (&error)) {
3238 mono_error_set_pending_exception (&error);
3239 return NULL;
3240 }
3241 MONO_OBJECT_SETREF (delegate, method_info, rm);
3242 }
3243
3244 if (!delegate->method_info || !delegate->method_info->method)
3245 g_assert_not_reached ();
3246
3247 klass = delegate->object.vtable->klass;
3248
3249 method = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3250 g_assert (method != NULL);
3251
3252 sig = mono_signature_no_pinvoke (method);
3253
3254 msg = mono_method_call_message_new (method, params, NULL, NULL, NULL, &error);
3255 if (mono_error_set_pending_exception (&error))
3256 return NULL;
3257
3258 ares = (MonoAsyncResult *)mono_array_get (msg->args, gpointer, sig->param_count - 1);
3259 if (ares == NULL) {
3260 mono_set_pending_exception (mono_exception_from_name_msg (mono_defaults.corlib, "System.Runtime.Remoting", "RemotingException", "The async result object is null or of an unexpected type."));
3261 return NULL;
3262 }
3263
3264 if (ares->async_delegate != (MonoObject*)delegate) {
3265 mono_set_pending_exception (mono_get_exception_invalid_operation (
3266 "The IAsyncResult object provided does not match this delegate."));
3267 return NULL;
3268 }
3269
3270 #ifndef DISABLE_REMOTING
3271 if (delegate->target && mono_object_is_transparent_proxy (delegate->target)) {
3272 MonoTransparentProxy* tp = (MonoTransparentProxy *)delegate->target;
3273 msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, &error);
3274 if (!mono_error_ok (&error)) {
3275 mono_error_set_pending_exception (&error);
3276 return NULL;
3277 }
3278 mono_message_init (domain, msg, delegate->method_info, NULL, &error);
3279 if (mono_error_set_pending_exception (&error))
3280 return NULL;
3281 msg->call_type = CallType_EndInvoke;
3282 MONO_OBJECT_SETREF (msg, async_result, ares);
3283 res = mono_remoting_invoke ((MonoObject *)tp->rp, msg, &exc, &out_args, &error);
3284 if (!mono_error_ok (&error)) {
3285 mono_error_set_pending_exception (&error);
3286 return NULL;
3287 }
3288 } else
3289 #endif
3290 {
3291 res = mono_threadpool_end_invoke (ares, &out_args, &exc, &error);
3292 if (mono_error_set_pending_exception (&error))
3293 return NULL;
3294 }
3295
3296 if (exc) {
3297 if (((MonoException*)exc)->stack_trace) {
3298 MonoError inner_error;
3299 char *strace = mono_string_to_utf8_checked (((MonoException*)exc)->stack_trace, &inner_error);
3300 if (is_ok (&inner_error)) {
3301 char *tmp;
3302 tmp = g_strdup_printf ("%s\nException Rethrown at:\n", strace);
3303 g_free (strace);
3304 MonoString *tmp_str = mono_string_new_checked (domain, tmp, &inner_error);
3305 g_free (tmp);
3306 if (is_ok (&inner_error))
3307 MONO_OBJECT_SETREF (((MonoException*)exc), stack_trace, tmp_str);
3308 };
3309 if (!is_ok (&inner_error))
3310 mono_error_cleanup (&inner_error); /* no stack trace, but at least throw the original exception */
3311 }
3312 mono_set_pending_exception ((MonoException*)exc);
3313 }
3314
3315 mono_method_return_message_restore (method, params, out_args, &error);
3316 mono_error_set_pending_exception (&error);
3317 return res;
3318 }
3319
3320 #ifdef ENABLE_ILGEN
3321
3322 void
mono_mb_emit_restore_result(MonoMethodBuilder * mb,MonoType * return_type)3323 mono_mb_emit_restore_result (MonoMethodBuilder *mb, MonoType *return_type)
3324 {
3325 MonoType *t = mono_type_get_underlying_type (return_type);
3326
3327 if (return_type->byref)
3328 return_type = &mono_defaults.int_class->byval_arg;
3329
3330 switch (t->type) {
3331 case MONO_TYPE_VOID:
3332 g_assert_not_reached ();
3333 break;
3334 case MONO_TYPE_PTR:
3335 case MONO_TYPE_STRING:
3336 case MONO_TYPE_CLASS:
3337 case MONO_TYPE_OBJECT:
3338 case MONO_TYPE_ARRAY:
3339 case MONO_TYPE_SZARRAY:
3340 /* nothing to do */
3341 break;
3342 case MONO_TYPE_U1:
3343 case MONO_TYPE_BOOLEAN:
3344 case MONO_TYPE_I1:
3345 case MONO_TYPE_U2:
3346 case MONO_TYPE_CHAR:
3347 case MONO_TYPE_I2:
3348 case MONO_TYPE_I:
3349 case MONO_TYPE_U:
3350 case MONO_TYPE_I4:
3351 case MONO_TYPE_U4:
3352 case MONO_TYPE_U8:
3353 case MONO_TYPE_I8:
3354 case MONO_TYPE_R4:
3355 case MONO_TYPE_R8:
3356 mono_mb_emit_op (mb, CEE_UNBOX, mono_class_from_mono_type (return_type));
3357 mono_mb_emit_byte (mb, mono_type_to_ldind (return_type));
3358 break;
3359 case MONO_TYPE_GENERICINST:
3360 if (!mono_type_generic_inst_is_valuetype (t))
3361 break;
3362 /* fall through */
3363 case MONO_TYPE_VALUETYPE: {
3364 MonoClass *klass = mono_class_from_mono_type (return_type);
3365 mono_mb_emit_op (mb, CEE_UNBOX, klass);
3366 mono_mb_emit_op (mb, CEE_LDOBJ, klass);
3367 break;
3368 }
3369 case MONO_TYPE_VAR:
3370 case MONO_TYPE_MVAR: {
3371 MonoClass *klass = mono_class_from_mono_type (return_type);
3372 mono_mb_emit_op (mb, CEE_UNBOX_ANY, klass);
3373 break;
3374 }
3375 default:
3376 g_warning ("type 0x%x not handled", return_type->type);
3377 g_assert_not_reached ();
3378 }
3379
3380 mono_mb_emit_byte (mb, CEE_RET);
3381 }
3382
3383 #endif /* ENABLE_ILGEN */
3384
3385 /**
3386 * mono_marshal_get_delegate_end_invoke:
3387 */
3388 MonoMethod *
mono_marshal_get_delegate_end_invoke(MonoMethod * method)3389 mono_marshal_get_delegate_end_invoke (MonoMethod *method)
3390 {
3391 MonoMethodSignature *sig;
3392 MonoMethodBuilder *mb;
3393 MonoMethod *res;
3394 GHashTable *cache;
3395 int params_var;
3396 char *name;
3397 MonoGenericContext *ctx = NULL;
3398 MonoMethod *orig_method = NULL;
3399
3400 g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
3401 !strcmp (method->name, "EndInvoke"));
3402
3403 /*
3404 * For generic delegates, create a generic wrapper, and returns an instance to help AOT.
3405 */
3406 if (method->is_inflated) {
3407 orig_method = method;
3408 ctx = &((MonoMethodInflated*)method)->context;
3409 method = ((MonoMethodInflated*)method)->declaring;
3410 }
3411
3412 sig = mono_signature_no_pinvoke (method);
3413
3414 /*
3415 * Check cache
3416 */
3417 if (ctx) {
3418 cache = get_cache (&((MonoMethodInflated*)orig_method)->owner->wrapper_caches.delegate_end_invoke_cache, mono_aligned_addr_hash, NULL);
3419 res = check_generic_delegate_wrapper_cache (cache, orig_method, method, ctx);
3420 if (res)
3421 return res;
3422 } else {
3423 cache = get_cache (&method->klass->image->wrapper_caches.delegate_end_invoke_cache,
3424 (GHashFunc)mono_signature_hash,
3425 (GCompareFunc)mono_metadata_signature_equal);
3426 if ((res = mono_marshal_find_in_cache (cache, sig)))
3427 return res;
3428 }
3429
3430 g_assert (sig->hasthis);
3431
3432 name = mono_signature_to_name (sig, "end_invoke");
3433 if (ctx)
3434 mb = mono_mb_new (method->klass, name, MONO_WRAPPER_DELEGATE_END_INVOKE);
3435 else
3436 mb = mono_mb_new (get_wrapper_target_class (method->klass->image), name, MONO_WRAPPER_DELEGATE_END_INVOKE);
3437 g_free (name);
3438
3439 #ifdef ENABLE_ILGEN
3440 params_var = mono_mb_emit_save_args (mb, sig, FALSE);
3441
3442 mono_mb_emit_ldarg (mb, 0);
3443 mono_mb_emit_ldloc (mb, params_var);
3444 mono_mb_emit_icall (mb, mono_delegate_end_invoke);
3445
3446 if (sig->ret->type == MONO_TYPE_VOID) {
3447 mono_mb_emit_byte (mb, CEE_POP);
3448 mono_mb_emit_byte (mb, CEE_RET);
3449 } else
3450 mono_mb_emit_restore_result (mb, sig->ret);
3451 #endif
3452
3453 if (ctx) {
3454 MonoMethod *def;
3455 def = mono_mb_create_and_cache (cache, method->klass, mb, sig, sig->param_count + 16);
3456 res = cache_generic_delegate_wrapper (cache, orig_method, def, ctx);
3457 } else {
3458 res = mono_mb_create_and_cache (cache, sig,
3459 mb, sig, sig->param_count + 16);
3460 }
3461 mono_mb_free (mb);
3462
3463 return res;
3464 }
3465
3466 typedef struct
3467 {
3468 MonoMethodSignature *sig;
3469 gpointer pointer;
3470 } SignaturePointerPair;
3471
3472 static guint
signature_pointer_pair_hash(gconstpointer data)3473 signature_pointer_pair_hash (gconstpointer data)
3474 {
3475 SignaturePointerPair *pair = (SignaturePointerPair*)data;
3476
3477 return mono_signature_hash (pair->sig) ^ mono_aligned_addr_hash (pair->pointer);
3478 }
3479
3480 static gboolean
signature_pointer_pair_equal(gconstpointer data1,gconstpointer data2)3481 signature_pointer_pair_equal (gconstpointer data1, gconstpointer data2)
3482 {
3483 SignaturePointerPair *pair1 = (SignaturePointerPair*) data1, *pair2 = (SignaturePointerPair*) data2;
3484 return mono_metadata_signature_equal (pair1->sig, pair2->sig) && (pair1->pointer == pair2->pointer);
3485 }
3486
3487 static gboolean
signature_pointer_pair_matches_pointer(gpointer key,gpointer value,gpointer user_data)3488 signature_pointer_pair_matches_pointer (gpointer key, gpointer value, gpointer user_data)
3489 {
3490 SignaturePointerPair *pair = (SignaturePointerPair*)key;
3491
3492 return pair->pointer == user_data;
3493 }
3494
3495 static void
free_signature_pointer_pair(SignaturePointerPair * pair)3496 free_signature_pointer_pair (SignaturePointerPair *pair)
3497 {
3498 g_free (pair);
3499 }
3500
3501 MonoMethod *
mono_marshal_get_delegate_invoke_internal(MonoMethod * method,gboolean callvirt,gboolean static_method_with_first_arg_bound,MonoMethod * target_method)3502 mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt, gboolean static_method_with_first_arg_bound, MonoMethod *target_method)
3503 {
3504 MonoMethodSignature *sig, *static_sig, *invoke_sig;
3505 int i;
3506 MonoMethodBuilder *mb;
3507 MonoMethod *res;
3508 GHashTable *cache;
3509 gpointer cache_key = NULL;
3510 SignaturePointerPair key = { NULL, NULL };
3511 SignaturePointerPair *new_key;
3512 int local_i, local_len, local_delegates, local_d, local_target, local_res;
3513 int pos0, pos1, pos2;
3514 char *name;
3515 MonoClass *target_class = NULL;
3516 gboolean closed_over_null = FALSE;
3517 MonoGenericContext *ctx = NULL;
3518 MonoGenericContainer *container = NULL;
3519 MonoMethod *orig_method = method;
3520 WrapperInfo *info;
3521 WrapperSubtype subtype = WRAPPER_SUBTYPE_NONE;
3522 gboolean found;
3523 gboolean void_ret;
3524
3525 g_assert (method && method->klass->parent == mono_defaults.multicastdelegate_class &&
3526 !strcmp (method->name, "Invoke"));
3527
3528 invoke_sig = sig = mono_signature_no_pinvoke (method);
3529
3530 /*
3531 * If the delegate target is null, and the target method is not static, a virtual
3532 * call is made to that method with the first delegate argument as this. This is
3533 * a non-documented .NET feature.
3534 */
3535 if (callvirt) {
3536 subtype = WRAPPER_SUBTYPE_DELEGATE_INVOKE_VIRTUAL;
3537 if (target_method->is_inflated) {
3538 MonoError error;
3539 MonoType *target_type;
3540
3541 g_assert (method->signature->hasthis);
3542 target_type = mono_class_inflate_generic_type_checked (method->signature->params [0],
3543 mono_method_get_context (method), &error);
3544 mono_error_assert_ok (&error); /* FIXME don't swallow the error */
3545 target_class = mono_class_from_mono_type (target_type);
3546 } else {
3547 target_class = target_method->klass;
3548 }
3549
3550 closed_over_null = sig->param_count == mono_method_signature (target_method)->param_count;
3551 }
3552
3553 if (static_method_with_first_arg_bound) {
3554 subtype = WRAPPER_SUBTYPE_DELEGATE_INVOKE_BOUND;
3555 g_assert (!callvirt);
3556 invoke_sig = mono_method_signature (target_method);
3557 }
3558
3559 /*
3560 * For generic delegates, create a generic wrapper, and return an instance to help AOT.
3561 */
3562 if (method->is_inflated && subtype == WRAPPER_SUBTYPE_NONE) {
3563 ctx = &((MonoMethodInflated*)method)->context;
3564 method = ((MonoMethodInflated*)method)->declaring;
3565
3566 container = mono_method_get_generic_container (method);
3567 if (!container)
3568 container = mono_class_try_get_generic_container (method->klass); //FIXME is this a case of a try?
3569 g_assert (container);
3570
3571 invoke_sig = sig = mono_signature_no_pinvoke (method);
3572 }
3573
3574 /*
3575 * Check cache
3576 */
3577 if (ctx) {
3578 cache = get_cache (&((MonoMethodInflated*)orig_method)->owner->wrapper_caches.delegate_invoke_cache, mono_aligned_addr_hash, NULL);
3579 res = check_generic_delegate_wrapper_cache (cache, orig_method, method, ctx);
3580 if (res)
3581 return res;
3582 cache_key = method->klass;
3583 } else if (static_method_with_first_arg_bound) {
3584 cache = get_cache (&method->klass->image->delegate_bound_static_invoke_cache,
3585 (GHashFunc)mono_signature_hash,
3586 (GCompareFunc)mono_metadata_signature_equal);
3587 /*
3588 * The wrapper is based on sig+invoke_sig, but sig can be derived from invoke_sig.
3589 */
3590 res = mono_marshal_find_in_cache (cache, invoke_sig);
3591 if (res)
3592 return res;
3593 cache_key = invoke_sig;
3594 } else if (callvirt) {
3595 GHashTable **cache_ptr;
3596
3597 cache_ptr = &mono_method_get_wrapper_cache (method)->delegate_abstract_invoke_cache;
3598
3599 /* We need to cache the signature+method pair */
3600 mono_marshal_lock ();
3601 if (!*cache_ptr)
3602 *cache_ptr = g_hash_table_new_full (signature_pointer_pair_hash, (GEqualFunc)signature_pointer_pair_equal, (GDestroyNotify)free_signature_pointer_pair, NULL);
3603 cache = *cache_ptr;
3604 key.sig = invoke_sig;
3605 key.pointer = target_method;
3606 res = (MonoMethod *)g_hash_table_lookup (cache, &key);
3607 mono_marshal_unlock ();
3608 if (res)
3609 return res;
3610 } else {
3611 // Inflated methods should not be in this cache because it's not stored on the imageset.
3612 g_assert (!method->is_inflated);
3613 cache = get_cache (&method->klass->image->wrapper_caches.delegate_invoke_cache,
3614 (GHashFunc)mono_signature_hash,
3615 (GCompareFunc)mono_metadata_signature_equal);
3616 res = mono_marshal_find_in_cache (cache, sig);
3617 if (res)
3618 return res;
3619 cache_key = sig;
3620 }
3621
3622 static_sig = mono_metadata_signature_dup_full (method->klass->image, sig);
3623 static_sig->hasthis = 0;
3624 if (!static_method_with_first_arg_bound)
3625 invoke_sig = static_sig;
3626
3627 if (static_method_with_first_arg_bound)
3628 name = mono_signature_to_name (invoke_sig, "invoke_bound");
3629 else if (closed_over_null)
3630 name = mono_signature_to_name (invoke_sig, "invoke_closed_over_null");
3631 else if (callvirt)
3632 name = mono_signature_to_name (invoke_sig, "invoke_callvirt");
3633 else
3634 name = mono_signature_to_name (invoke_sig, "invoke");
3635 if (ctx)
3636 mb = mono_mb_new (method->klass, name, MONO_WRAPPER_DELEGATE_INVOKE);
3637 else
3638 mb = mono_mb_new (get_wrapper_target_class (method->klass->image), name, MONO_WRAPPER_DELEGATE_INVOKE);
3639 g_free (name);
3640
3641 #ifdef ENABLE_ILGEN
3642 void_ret = sig->ret->type == MONO_TYPE_VOID && !method->string_ctor;
3643
3644 /* allocate local 0 (object) */
3645 local_i = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
3646 local_len = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
3647 local_delegates = mono_mb_add_local (mb, &mono_defaults.array_class->byval_arg);
3648 local_d = mono_mb_add_local (mb, &mono_defaults.multicastdelegate_class->byval_arg);
3649 local_target = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
3650
3651 if (!void_ret)
3652 local_res = mono_mb_add_local (mb, &mono_class_from_mono_type (sig->ret)->byval_arg);
3653
3654 g_assert (sig->hasthis);
3655
3656 /*
3657 * {type: sig->ret} res;
3658 * if (delegates == null) {
3659 * return this.<target> ( args .. );
3660 * } else {
3661 * int i = 0, len = this.delegates.Length;
3662 * do {
3663 * res = this.delegates [i].Invoke ( args .. );
3664 * } while (++i < len);
3665 * return res;
3666 * }
3667 */
3668
3669 /* this wrapper can be used in unmanaged-managed transitions */
3670 emit_thread_interrupt_checkpoint (mb);
3671
3672 /* delegates = this.delegates */
3673 mono_mb_emit_ldarg (mb, 0);
3674 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoMulticastDelegate, delegates));
3675 mono_mb_emit_byte (mb, CEE_LDIND_REF);
3676 mono_mb_emit_stloc (mb, local_delegates);
3677
3678 /* if (delegates == null) */
3679 mono_mb_emit_ldloc (mb, local_delegates);
3680 pos2 = mono_mb_emit_branch (mb, CEE_BRTRUE);
3681
3682 /* return target.<target_method|method_ptr> ( args .. ); */
3683
3684 /* target = d.target; */
3685 mono_mb_emit_ldarg (mb, 0);
3686 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, target));
3687 mono_mb_emit_byte (mb, CEE_LDIND_REF);
3688 mono_mb_emit_stloc (mb, local_target);
3689
3690 /*static methods with bound first arg can have null target and still be bound*/
3691 if (!static_method_with_first_arg_bound) {
3692 /* if target != null */
3693 mono_mb_emit_ldloc (mb, local_target);
3694 pos0 = mono_mb_emit_branch (mb, CEE_BRFALSE);
3695
3696 /* then call this->method_ptr nonstatic */
3697 if (callvirt) {
3698 // FIXME:
3699 mono_mb_emit_exception_full (mb, "System", "NotImplementedException", "");
3700 } else {
3701 mono_mb_emit_ldloc (mb, local_target);
3702 for (i = 0; i < sig->param_count; ++i)
3703 mono_mb_emit_ldarg (mb, i + 1);
3704 mono_mb_emit_ldarg (mb, 0);
3705 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, extra_arg));
3706 mono_mb_emit_byte (mb, CEE_LDIND_I);
3707 mono_mb_emit_ldarg (mb, 0);
3708 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
3709 mono_mb_emit_byte (mb, CEE_LDIND_I);
3710 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
3711 mono_mb_emit_op (mb, CEE_MONO_CALLI_EXTRA_ARG, sig);
3712 mono_mb_emit_byte (mb, CEE_RET);
3713 }
3714
3715 /* else [target == null] call this->method_ptr static */
3716 mono_mb_patch_branch (mb, pos0);
3717 }
3718
3719 if (callvirt) {
3720 if (!closed_over_null) {
3721 if (target_class->valuetype) {
3722 mono_mb_emit_ldarg (mb, 1);
3723 for (i = 1; i < sig->param_count; ++i)
3724 mono_mb_emit_ldarg (mb, i + 1);
3725 mono_mb_emit_op (mb, CEE_CALL, target_method);
3726 } else {
3727 mono_mb_emit_ldarg (mb, 1);
3728 mono_mb_emit_op (mb, CEE_CASTCLASS, target_class);
3729 for (i = 1; i < sig->param_count; ++i)
3730 mono_mb_emit_ldarg (mb, i + 1);
3731 mono_mb_emit_op (mb, CEE_CALLVIRT, target_method);
3732 }
3733 } else {
3734 mono_mb_emit_byte (mb, CEE_LDNULL);
3735 for (i = 0; i < sig->param_count; ++i)
3736 mono_mb_emit_ldarg (mb, i + 1);
3737 mono_mb_emit_op (mb, CEE_CALL, target_method);
3738 }
3739 } else {
3740 if (static_method_with_first_arg_bound) {
3741 mono_mb_emit_ldloc (mb, local_target);
3742 if (!MONO_TYPE_IS_REFERENCE (invoke_sig->params[0]))
3743 mono_mb_emit_op (mb, CEE_UNBOX_ANY, mono_class_from_mono_type (invoke_sig->params[0]));
3744 }
3745 for (i = 0; i < sig->param_count; ++i)
3746 mono_mb_emit_ldarg (mb, i + 1);
3747 mono_mb_emit_ldarg (mb, 0);
3748 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, extra_arg));
3749 mono_mb_emit_byte (mb, CEE_LDIND_I);
3750 mono_mb_emit_ldarg (mb, 0);
3751 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
3752 mono_mb_emit_byte (mb, CEE_LDIND_I);
3753 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
3754 mono_mb_emit_op (mb, CEE_MONO_CALLI_EXTRA_ARG, invoke_sig);
3755 }
3756
3757 mono_mb_emit_byte (mb, CEE_RET);
3758
3759 /* else [delegates != null] */
3760 mono_mb_patch_branch (mb, pos2);
3761
3762 /* len = delegates.Length; */
3763 mono_mb_emit_ldloc (mb, local_delegates);
3764 mono_mb_emit_byte (mb, CEE_LDLEN);
3765 mono_mb_emit_byte (mb, CEE_CONV_I4);
3766 mono_mb_emit_stloc (mb, local_len);
3767
3768 /* i = 0; */
3769 mono_mb_emit_icon (mb, 0);
3770 mono_mb_emit_stloc (mb, local_i);
3771
3772 pos1 = mono_mb_get_label (mb);
3773
3774 /* d = delegates [i]; */
3775 mono_mb_emit_ldloc (mb, local_delegates);
3776 mono_mb_emit_ldloc (mb, local_i);
3777 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
3778 mono_mb_emit_stloc (mb, local_d);
3779
3780 /* res = d.Invoke ( args .. ); */
3781 mono_mb_emit_ldloc (mb, local_d);
3782 for (i = 0; i < sig->param_count; i++)
3783 mono_mb_emit_ldarg (mb, i + 1);
3784 if (!ctx) {
3785 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
3786 } else {
3787 MonoError error;
3788 mono_mb_emit_op (mb, CEE_CALLVIRT, mono_class_inflate_generic_method_checked (method, &container->context, &error));
3789 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
3790 }
3791 if (!void_ret)
3792 mono_mb_emit_stloc (mb, local_res);
3793
3794 /* i += 1 */
3795 mono_mb_emit_add_to_local (mb, local_i, 1);
3796
3797 /* i < l */
3798 mono_mb_emit_ldloc (mb, local_i);
3799 mono_mb_emit_ldloc (mb, local_len);
3800 mono_mb_emit_branch_label (mb, CEE_BLT, pos1);
3801
3802 /* return res */
3803 if (!void_ret)
3804 mono_mb_emit_ldloc (mb, local_res);
3805 mono_mb_emit_byte (mb, CEE_RET);
3806
3807 mb->skip_visibility = 1;
3808 #endif /* ENABLE_ILGEN */
3809
3810 info = mono_wrapper_info_create (mb, subtype);
3811 info->d.delegate_invoke.method = method;
3812
3813 if (ctx) {
3814 MonoMethod *def;
3815
3816 def = mono_mb_create_and_cache_full (cache, cache_key, mb, sig, sig->param_count + 16, info, NULL);
3817 res = cache_generic_delegate_wrapper (cache, orig_method, def, ctx);
3818 } else if (callvirt) {
3819 new_key = g_new0 (SignaturePointerPair, 1);
3820 *new_key = key;
3821
3822 res = mono_mb_create_and_cache_full (cache, new_key, mb, sig, sig->param_count + 16, info, &found);
3823 if (found)
3824 g_free (new_key);
3825 } else {
3826 res = mono_mb_create_and_cache_full (cache, cache_key, mb, sig, sig->param_count + 16, info, NULL);
3827 }
3828 mono_mb_free (mb);
3829
3830 /* mono_method_print_code (res); */
3831
3832 return res;
3833 }
3834
3835 /**
3836 * mono_marshal_get_delegate_invoke:
3837 * The returned method invokes all methods in a multicast delegate.
3838 */
3839 MonoMethod *
mono_marshal_get_delegate_invoke(MonoMethod * method,MonoDelegate * del)3840 mono_marshal_get_delegate_invoke (MonoMethod *method, MonoDelegate *del)
3841 {
3842 gboolean callvirt = FALSE;
3843 gboolean static_method_with_first_arg_bound = FALSE;
3844 MonoMethod *target_method = NULL;
3845 MonoMethodSignature *sig;
3846
3847 sig = mono_signature_no_pinvoke (method);
3848
3849 if (del && !del->target && del->method && mono_method_signature (del->method)->hasthis) {
3850 callvirt = TRUE;
3851 target_method = del->method;
3852 }
3853
3854 if (del && del->method && mono_method_signature (del->method)->param_count == sig->param_count + 1 && (del->method->flags & METHOD_ATTRIBUTE_STATIC)) {
3855 static_method_with_first_arg_bound = TRUE;
3856 target_method = del->method;
3857 }
3858
3859 return mono_marshal_get_delegate_invoke_internal (method, callvirt, static_method_with_first_arg_bound, target_method);
3860 }
3861
3862 typedef struct {
3863 MonoMethodSignature *ctor_sig;
3864 MonoMethodSignature *sig;
3865 } CtorSigPair;
3866
3867 /* protected by the marshal lock, contains CtorSigPair pointers */
3868 static GSList *strsig_list = NULL;
3869
3870 static MonoMethodSignature *
lookup_string_ctor_signature(MonoMethodSignature * sig)3871 lookup_string_ctor_signature (MonoMethodSignature *sig)
3872 {
3873 MonoMethodSignature *callsig;
3874 CtorSigPair *cs;
3875 GSList *item;
3876
3877 mono_marshal_lock ();
3878 callsig = NULL;
3879 for (item = strsig_list; item; item = item->next) {
3880 cs = (CtorSigPair *)item->data;
3881 /* mono_metadata_signature_equal () is safe to call with the marshal lock
3882 * because it is lock-free.
3883 */
3884 if (mono_metadata_signature_equal (sig, cs->ctor_sig)) {
3885 callsig = cs->sig;
3886 break;
3887 }
3888 }
3889 mono_marshal_unlock ();
3890 return callsig;
3891 }
3892
3893 static MonoMethodSignature *
add_string_ctor_signature(MonoMethod * method)3894 add_string_ctor_signature (MonoMethod *method)
3895 {
3896 MonoMethodSignature *callsig;
3897 CtorSigPair *cs;
3898
3899 callsig = mono_metadata_signature_dup_full (method->klass->image, mono_method_signature (method));
3900 callsig->ret = &mono_defaults.string_class->byval_arg;
3901 cs = g_new (CtorSigPair, 1);
3902 cs->sig = callsig;
3903 cs->ctor_sig = mono_method_signature (method);
3904
3905 mono_marshal_lock ();
3906 strsig_list = g_slist_prepend (strsig_list, cs);
3907 mono_marshal_unlock ();
3908 return callsig;
3909 }
3910
3911 /*
3912 * mono_marshal_get_string_ctor_signature:
3913 *
3914 * Return the modified signature used by string ctors (they return the newly created
3915 * string).
3916 */
3917 MonoMethodSignature*
mono_marshal_get_string_ctor_signature(MonoMethod * method)3918 mono_marshal_get_string_ctor_signature (MonoMethod *method)
3919 {
3920 MonoMethodSignature *sig = lookup_string_ctor_signature (mono_method_signature (method));
3921 if (!sig)
3922 sig = add_string_ctor_signature (method);
3923
3924 return sig;
3925 }
3926
3927 static MonoType*
get_runtime_invoke_type(MonoType * t,gboolean ret)3928 get_runtime_invoke_type (MonoType *t, gboolean ret)
3929 {
3930 if (t->byref) {
3931 if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
3932 return t;
3933 /* Can't share this with 'I' as that needs another indirection */
3934 return &mono_defaults.int_class->this_arg;
3935 }
3936
3937 if (MONO_TYPE_IS_REFERENCE (t))
3938 return &mono_defaults.object_class->byval_arg;
3939
3940 if (ret)
3941 /* The result needs to be boxed */
3942 return t;
3943
3944 handle_enum:
3945 switch (t->type) {
3946 /* Can't share these as the argument needs to be loaded using sign/zero extension */
3947 /*
3948 case MONO_TYPE_U1:
3949 return &mono_defaults.sbyte_class->byval_arg;
3950 case MONO_TYPE_U2:
3951 return &mono_defaults.int16_class->byval_arg;
3952 case MONO_TYPE_U4:
3953 return &mono_defaults.int32_class->byval_arg;
3954 */
3955 case MONO_TYPE_U8:
3956 return &mono_defaults.int64_class->byval_arg;
3957 case MONO_TYPE_BOOLEAN:
3958 return &mono_defaults.byte_class->byval_arg;
3959 case MONO_TYPE_CHAR:
3960 return &mono_defaults.uint16_class->byval_arg;
3961 case MONO_TYPE_U:
3962 return &mono_defaults.int_class->byval_arg;
3963 case MONO_TYPE_VALUETYPE:
3964 if (t->data.klass->enumtype) {
3965 t = mono_class_enum_basetype (t->data.klass);
3966 goto handle_enum;
3967 }
3968 return t;
3969 default:
3970 return t;
3971 }
3972 }
3973
3974 /*
3975 * mono_marshal_get_runtime_invoke_sig:
3976 *
3977 * Return a common signature used for sharing runtime invoke wrappers.
3978 */
3979 static MonoMethodSignature*
mono_marshal_get_runtime_invoke_sig(MonoMethodSignature * sig)3980 mono_marshal_get_runtime_invoke_sig (MonoMethodSignature *sig)
3981 {
3982 MonoMethodSignature *res = mono_metadata_signature_dup (sig);
3983 int i;
3984
3985 res->generic_param_count = 0;
3986 res->ret = get_runtime_invoke_type (sig->ret, TRUE);
3987 for (i = 0; i < res->param_count; ++i)
3988 res->params [i] = get_runtime_invoke_type (sig->params [i], FALSE);
3989
3990 return res;
3991 }
3992
3993 static gboolean
runtime_invoke_signature_equal(MonoMethodSignature * sig1,MonoMethodSignature * sig2)3994 runtime_invoke_signature_equal (MonoMethodSignature *sig1, MonoMethodSignature *sig2)
3995 {
3996 /* Can't share wrappers which return a vtype since it needs to be boxed */
3997 if (sig1->ret != sig2->ret && !(MONO_TYPE_IS_REFERENCE (sig1->ret) && MONO_TYPE_IS_REFERENCE (sig2->ret)) && !mono_metadata_type_equal (sig1->ret, sig2->ret))
3998 return FALSE;
3999 else
4000 return mono_metadata_signature_equal (sig1, sig2);
4001 }
4002
4003 #ifdef ENABLE_ILGEN
4004
4005 /*
4006 * emit_invoke_call:
4007 *
4008 * Emit the call to the wrapper method from a runtime invoke wrapper.
4009 */
4010 static void
emit_invoke_call(MonoMethodBuilder * mb,MonoMethod * method,MonoMethodSignature * sig,MonoMethodSignature * callsig,int loc_res,gboolean virtual_,gboolean need_direct_wrapper)4011 emit_invoke_call (MonoMethodBuilder *mb, MonoMethod *method,
4012 MonoMethodSignature *sig, MonoMethodSignature *callsig,
4013 int loc_res,
4014 gboolean virtual_, gboolean need_direct_wrapper)
4015 {
4016 static MonoString *string_dummy = NULL;
4017 int i;
4018 int *tmp_nullable_locals;
4019 gboolean void_ret = FALSE;
4020 gboolean string_ctor = method && method->string_ctor;
4021
4022 /* to make it work with our special string constructors */
4023 if (!string_dummy) {
4024 MonoError error;
4025 MONO_GC_REGISTER_ROOT_SINGLE (string_dummy, MONO_ROOT_SOURCE_MARSHAL, "dummy marshal string");
4026 string_dummy = mono_string_new_checked (mono_get_root_domain (), "dummy", &error);
4027 mono_error_assert_ok (&error);
4028 }
4029
4030 if (virtual_) {
4031 g_assert (sig->hasthis);
4032 g_assert (method->flags & METHOD_ATTRIBUTE_VIRTUAL);
4033 }
4034
4035 if (sig->hasthis) {
4036 if (string_ctor) {
4037 if (mono_gc_is_moving ()) {
4038 mono_mb_emit_ptr (mb, &string_dummy);
4039 mono_mb_emit_byte (mb, CEE_LDIND_REF);
4040 } else {
4041 mono_mb_emit_ptr (mb, string_dummy);
4042 }
4043 } else {
4044 mono_mb_emit_ldarg (mb, 0);
4045 }
4046 }
4047
4048 tmp_nullable_locals = g_new0 (int, sig->param_count);
4049
4050 for (i = 0; i < sig->param_count; i++) {
4051 MonoType *t = sig->params [i];
4052 int type;
4053
4054 mono_mb_emit_ldarg (mb, 1);
4055 if (i) {
4056 mono_mb_emit_icon (mb, sizeof (gpointer) * i);
4057 mono_mb_emit_byte (mb, CEE_ADD);
4058 }
4059
4060 if (t->byref) {
4061 mono_mb_emit_byte (mb, CEE_LDIND_I);
4062 /* A Nullable<T> type don't have a boxed form, it's either null or a boxed T.
4063 * So to make this work we unbox it to a local variablee and push a reference to that.
4064 */
4065 if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
4066 tmp_nullable_locals [i] = mono_mb_add_local (mb, &mono_class_from_mono_type (t)->byval_arg);
4067
4068 mono_mb_emit_op (mb, CEE_UNBOX_ANY, mono_class_from_mono_type (t));
4069 mono_mb_emit_stloc (mb, tmp_nullable_locals [i]);
4070 mono_mb_emit_ldloc_addr (mb, tmp_nullable_locals [i]);
4071 }
4072 continue;
4073 }
4074
4075 /*FIXME 'this doesn't handle generic enums. Shouldn't we?*/
4076 type = sig->params [i]->type;
4077 handle_enum:
4078 switch (type) {
4079 case MONO_TYPE_I1:
4080 case MONO_TYPE_BOOLEAN:
4081 case MONO_TYPE_U1:
4082 case MONO_TYPE_I2:
4083 case MONO_TYPE_U2:
4084 case MONO_TYPE_CHAR:
4085 case MONO_TYPE_I:
4086 case MONO_TYPE_U:
4087 case MONO_TYPE_I4:
4088 case MONO_TYPE_U4:
4089 case MONO_TYPE_R4:
4090 case MONO_TYPE_R8:
4091 case MONO_TYPE_I8:
4092 case MONO_TYPE_U8:
4093 mono_mb_emit_byte (mb, CEE_LDIND_I);
4094 mono_mb_emit_byte (mb, mono_type_to_ldind (sig->params [i]));
4095 break;
4096 case MONO_TYPE_STRING:
4097 case MONO_TYPE_CLASS:
4098 case MONO_TYPE_ARRAY:
4099 case MONO_TYPE_PTR:
4100 case MONO_TYPE_SZARRAY:
4101 case MONO_TYPE_OBJECT:
4102 mono_mb_emit_byte (mb, mono_type_to_ldind (sig->params [i]));
4103 break;
4104 case MONO_TYPE_GENERICINST:
4105 if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
4106 mono_mb_emit_byte (mb, mono_type_to_ldind (sig->params [i]));
4107 break;
4108 }
4109
4110 /* fall through */
4111 case MONO_TYPE_VALUETYPE:
4112 if (type == MONO_TYPE_VALUETYPE && t->data.klass->enumtype) {
4113 type = mono_class_enum_basetype (t->data.klass)->type;
4114 goto handle_enum;
4115 }
4116 mono_mb_emit_byte (mb, CEE_LDIND_I);
4117 if (mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
4118 /* Need to convert a boxed vtype to an mp to a Nullable struct */
4119 mono_mb_emit_op (mb, CEE_UNBOX, mono_class_from_mono_type (sig->params [i]));
4120 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i]));
4121 } else {
4122 mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type (sig->params [i]));
4123 }
4124 break;
4125 default:
4126 g_assert_not_reached ();
4127 }
4128 }
4129
4130 if (virtual_) {
4131 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
4132 } else if (need_direct_wrapper) {
4133 mono_mb_emit_op (mb, CEE_CALL, method);
4134 } else {
4135 mono_mb_emit_ldarg (mb, 3);
4136 mono_mb_emit_calli (mb, callsig);
4137 }
4138
4139 if (sig->ret->byref) {
4140 /* fixme: */
4141 g_assert_not_reached ();
4142 }
4143
4144 switch (sig->ret->type) {
4145 case MONO_TYPE_VOID:
4146 if (!string_ctor)
4147 void_ret = TRUE;
4148 break;
4149 case MONO_TYPE_BOOLEAN:
4150 case MONO_TYPE_CHAR:
4151 case MONO_TYPE_I1:
4152 case MONO_TYPE_U1:
4153 case MONO_TYPE_I2:
4154 case MONO_TYPE_U2:
4155 case MONO_TYPE_I4:
4156 case MONO_TYPE_U4:
4157 case MONO_TYPE_I:
4158 case MONO_TYPE_U:
4159 case MONO_TYPE_R4:
4160 case MONO_TYPE_R8:
4161 case MONO_TYPE_I8:
4162 case MONO_TYPE_U8:
4163 case MONO_TYPE_VALUETYPE:
4164 case MONO_TYPE_TYPEDBYREF:
4165 case MONO_TYPE_GENERICINST:
4166 /* box value types */
4167 mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type (sig->ret));
4168 break;
4169 case MONO_TYPE_STRING:
4170 case MONO_TYPE_CLASS:
4171 case MONO_TYPE_ARRAY:
4172 case MONO_TYPE_SZARRAY:
4173 case MONO_TYPE_OBJECT:
4174 /* nothing to do */
4175 break;
4176 case MONO_TYPE_PTR:
4177 /* The result is an IntPtr */
4178 mono_mb_emit_op (mb, CEE_BOX, mono_defaults.int_class);
4179 break;
4180 default:
4181 g_assert_not_reached ();
4182 }
4183
4184 if (!void_ret)
4185 mono_mb_emit_stloc (mb, loc_res);
4186
4187 /* Convert back nullable-byref arguments */
4188 for (i = 0; i < sig->param_count; i++) {
4189 MonoType *t = sig->params [i];
4190
4191 /*
4192 * Box the result and put it back into the array, the caller will have
4193 * to obtain it from there.
4194 */
4195 if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
4196 mono_mb_emit_ldarg (mb, 1);
4197 mono_mb_emit_icon (mb, sizeof (gpointer) * i);
4198 mono_mb_emit_byte (mb, CEE_ADD);
4199
4200 mono_mb_emit_ldloc (mb, tmp_nullable_locals [i]);
4201 mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type (t));
4202
4203 mono_mb_emit_byte (mb, CEE_STIND_REF);
4204 }
4205 }
4206
4207 g_free (tmp_nullable_locals);
4208 }
4209
4210 static void
emit_runtime_invoke_body(MonoMethodBuilder * mb,MonoImage * image,MonoMethod * method,MonoMethodSignature * sig,MonoMethodSignature * callsig,gboolean virtual_,gboolean need_direct_wrapper)4211 emit_runtime_invoke_body (MonoMethodBuilder *mb, MonoImage *image, MonoMethod *method,
4212 MonoMethodSignature *sig, MonoMethodSignature *callsig,
4213 gboolean virtual_, gboolean need_direct_wrapper)
4214 {
4215 gint32 labels [16];
4216 MonoExceptionClause *clause;
4217 int loc_res, loc_exc;
4218
4219 /* The wrapper looks like this:
4220 *
4221 * <interrupt check>
4222 * if (exc) {
4223 * try {
4224 * return <call>
4225 * } catch (Exception e) {
4226 * *exc = e;
4227 * }
4228 * } else {
4229 * return <call>
4230 * }
4231 */
4232
4233 /* allocate local 0 (object) tmp */
4234 loc_res = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
4235 /* allocate local 1 (object) exc */
4236 loc_exc = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
4237
4238 /* *exc is assumed to be initialized to NULL by the caller */
4239
4240 mono_mb_emit_byte (mb, CEE_LDARG_2);
4241 labels [0] = mono_mb_emit_branch (mb, CEE_BRFALSE);
4242
4243 /*
4244 * if (exc) case
4245 */
4246 labels [1] = mono_mb_get_label (mb);
4247 emit_thread_force_interrupt_checkpoint (mb);
4248 emit_invoke_call (mb, method, sig, callsig, loc_res, virtual_, need_direct_wrapper);
4249
4250 labels [2] = mono_mb_emit_branch (mb, CEE_LEAVE);
4251
4252 /* Add a try clause around the call */
4253 clause = (MonoExceptionClause *)mono_image_alloc0 (image, sizeof (MonoExceptionClause));
4254 clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
4255 clause->data.catch_class = mono_defaults.exception_class;
4256 clause->try_offset = labels [1];
4257 clause->try_len = mono_mb_get_label (mb) - labels [1];
4258
4259 clause->handler_offset = mono_mb_get_label (mb);
4260
4261 /* handler code */
4262 mono_mb_emit_stloc (mb, loc_exc);
4263 mono_mb_emit_byte (mb, CEE_LDARG_2);
4264 mono_mb_emit_ldloc (mb, loc_exc);
4265 mono_mb_emit_byte (mb, CEE_STIND_REF);
4266
4267 mono_mb_emit_branch (mb, CEE_LEAVE);
4268
4269 clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset;
4270
4271 mono_mb_set_clauses (mb, 1, clause);
4272
4273 mono_mb_patch_branch (mb, labels [2]);
4274 mono_mb_emit_ldloc (mb, loc_res);
4275 mono_mb_emit_byte (mb, CEE_RET);
4276
4277 /*
4278 * if (!exc) case
4279 */
4280 mono_mb_patch_branch (mb, labels [0]);
4281 emit_thread_force_interrupt_checkpoint (mb);
4282 emit_invoke_call (mb, method, sig, callsig, loc_res, virtual_, need_direct_wrapper);
4283
4284 mono_mb_emit_ldloc (mb, 0);
4285 mono_mb_emit_byte (mb, CEE_RET);
4286 }
4287 #endif
4288
4289 /**
4290 * mono_marshal_get_runtime_invoke:
4291 * Generates IL code for the runtime invoke function:
4292 *
4293 * <code>MonoObject *runtime_invoke (MonoObject *this_obj, void **params, MonoObject **exc, void* method)</code>
4294 *
4295 * We also catch exceptions if \p exc is not NULL.
4296 * If \p virtual is TRUE, then \p method is invoked virtually on \p this. This is useful since
4297 * it means that the compiled code for \p method does not have to be looked up
4298 * before calling the runtime invoke wrapper. In this case, the wrapper ignores
4299 * its \p method argument.
4300 */
4301 MonoMethod *
mono_marshal_get_runtime_invoke_full(MonoMethod * method,gboolean virtual_,gboolean need_direct_wrapper)4302 mono_marshal_get_runtime_invoke_full (MonoMethod *method, gboolean virtual_, gboolean need_direct_wrapper)
4303 {
4304 MonoMethodSignature *sig, *csig, *callsig;
4305 MonoMethodBuilder *mb;
4306 GHashTable *cache = NULL;
4307 MonoClass *target_klass;
4308 MonoMethod *res = NULL;
4309 static MonoMethodSignature *cctor_signature = NULL;
4310 static MonoMethodSignature *finalize_signature = NULL;
4311 char *name;
4312 const char *param_names [16];
4313 WrapperInfo *info;
4314
4315 g_assert (method);
4316
4317 if (!cctor_signature) {
4318 cctor_signature = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
4319 cctor_signature->ret = &mono_defaults.void_class->byval_arg;
4320 }
4321 if (!finalize_signature) {
4322 finalize_signature = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
4323 finalize_signature->ret = &mono_defaults.void_class->byval_arg;
4324 finalize_signature->hasthis = 1;
4325 }
4326
4327 /*
4328 * Use a separate cache indexed by methods to speed things up and to avoid the
4329 * boundless mempool growth caused by the signature_dup stuff below.
4330 */
4331 if (virtual_)
4332 cache = get_cache (&method->klass->image->runtime_invoke_vcall_cache, mono_aligned_addr_hash, NULL);
4333 else
4334 cache = get_cache (&mono_method_get_wrapper_cache (method)->runtime_invoke_direct_cache, mono_aligned_addr_hash, NULL);
4335
4336 res = mono_marshal_find_in_cache (cache, method);
4337 if (res)
4338 return res;
4339
4340 if (method->string_ctor) {
4341 callsig = lookup_string_ctor_signature (mono_method_signature (method));
4342 if (!callsig)
4343 callsig = add_string_ctor_signature (method);
4344 } else {
4345 if (method_is_dynamic (method))
4346 callsig = mono_metadata_signature_dup_full (method->klass->image, mono_method_signature (method));
4347 else
4348 callsig = mono_method_signature (method);
4349 }
4350
4351 sig = mono_method_signature (method);
4352
4353 target_klass = get_wrapper_target_class (method->klass->image);
4354
4355 /* Try to share wrappers for non-corlib methods with simple signatures */
4356 if (mono_metadata_signature_equal (callsig, cctor_signature)) {
4357 callsig = cctor_signature;
4358 target_klass = mono_defaults.object_class;
4359 } else if (mono_metadata_signature_equal (callsig, finalize_signature)) {
4360 callsig = finalize_signature;
4361 target_klass = mono_defaults.object_class;
4362 }
4363
4364 if (need_direct_wrapper) {
4365 /* Already searched at the start */
4366 } else {
4367 MonoMethodSignature *tmp_sig;
4368
4369 callsig = mono_marshal_get_runtime_invoke_sig (callsig);
4370 GHashTable **cache_table = NULL;
4371
4372 if (method->klass->valuetype && mono_method_signature (method)->hasthis)
4373 cache_table = &mono_method_get_wrapper_cache (method)->runtime_invoke_vtype_cache;
4374 else
4375 cache_table = &mono_method_get_wrapper_cache (method)->runtime_invoke_cache;
4376
4377 cache = get_cache (cache_table, (GHashFunc)mono_signature_hash,
4378 (GCompareFunc)runtime_invoke_signature_equal);
4379
4380 /* from mono_marshal_find_in_cache */
4381 mono_marshal_lock ();
4382 res = (MonoMethod *)g_hash_table_lookup (cache, callsig);
4383 mono_marshal_unlock ();
4384
4385 if (res) {
4386 g_free (callsig);
4387 return res;
4388 }
4389
4390 /* Make a copy of the signature from the image mempool */
4391 tmp_sig = callsig;
4392 callsig = mono_metadata_signature_dup_full (target_klass->image, callsig);
4393 g_free (tmp_sig);
4394 }
4395
4396 csig = mono_metadata_signature_alloc (target_klass->image, 4);
4397
4398 csig->ret = &mono_defaults.object_class->byval_arg;
4399 if (method->klass->valuetype && mono_method_signature (method)->hasthis)
4400 csig->params [0] = get_runtime_invoke_type (&method->klass->this_arg, FALSE);
4401 else
4402 csig->params [0] = &mono_defaults.object_class->byval_arg;
4403 csig->params [1] = &mono_defaults.int_class->byval_arg;
4404 csig->params [2] = &mono_defaults.int_class->byval_arg;
4405 csig->params [3] = &mono_defaults.int_class->byval_arg;
4406 csig->pinvoke = 1;
4407 #if TARGET_WIN32
4408 /* This is called from runtime code so it has to be cdecl */
4409 csig->call_convention = MONO_CALL_C;
4410 #endif
4411
4412 name = mono_signature_to_name (callsig, virtual_ ? "runtime_invoke_virtual" : (need_direct_wrapper ? "runtime_invoke_direct" : "runtime_invoke"));
4413 mb = mono_mb_new (target_klass, name, MONO_WRAPPER_RUNTIME_INVOKE);
4414 g_free (name);
4415
4416 #ifdef ENABLE_ILGEN
4417 param_names [0] = "this";
4418 param_names [1] = "params";
4419 param_names [2] = "exc";
4420 param_names [3] = "method";
4421 mono_mb_set_param_names (mb, param_names);
4422
4423 emit_runtime_invoke_body (mb, target_klass->image, method, sig, callsig, virtual_, need_direct_wrapper);
4424 #endif
4425
4426 if (need_direct_wrapper) {
4427 #ifdef ENABLE_ILGEN
4428 mb->skip_visibility = 1;
4429 #endif
4430 info = mono_wrapper_info_create (mb, virtual_ ? WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL : WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT);
4431 info->d.runtime_invoke.method = method;
4432 res = mono_mb_create_and_cache_full (cache, method, mb, csig, sig->param_count + 16, info, NULL);
4433 } else {
4434 /* taken from mono_mb_create_and_cache */
4435 mono_marshal_lock ();
4436 res = (MonoMethod *)g_hash_table_lookup (cache, callsig);
4437 mono_marshal_unlock ();
4438
4439 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_RUNTIME_INVOKE_NORMAL);
4440 info->d.runtime_invoke.sig = callsig;
4441
4442 /* Somebody may have created it before us */
4443 if (!res) {
4444 MonoMethod *newm;
4445 newm = mono_mb_create (mb, csig, sig->param_count + 16, info);
4446
4447 mono_marshal_lock ();
4448 res = (MonoMethod *)g_hash_table_lookup (cache, callsig);
4449 if (!res) {
4450 GHashTable *direct_cache;
4451 res = newm;
4452 g_hash_table_insert (cache, callsig, res);
4453 /* Can't insert it into wrapper_hash since the key is a signature */
4454 direct_cache = mono_method_get_wrapper_cache (method)->runtime_invoke_direct_cache;
4455
4456 g_hash_table_insert (direct_cache, method, res);
4457 } else {
4458 mono_free_method (newm);
4459 }
4460 mono_marshal_unlock ();
4461 }
4462
4463 /* end mono_mb_create_and_cache */
4464 }
4465
4466 mono_mb_free (mb);
4467
4468 return res;
4469 }
4470
4471 MonoMethod *
mono_marshal_get_runtime_invoke(MonoMethod * method,gboolean virtual_)4472 mono_marshal_get_runtime_invoke (MonoMethod *method, gboolean virtual_)
4473 {
4474 gboolean need_direct_wrapper = FALSE;
4475
4476 if (virtual_)
4477 need_direct_wrapper = TRUE;
4478
4479 if (method->dynamic)
4480 need_direct_wrapper = TRUE;
4481
4482 if (method->klass->rank && (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
4483 (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)) {
4484 /*
4485 * Array Get/Set/Address methods. The JIT implements them using inline code
4486 * so we need to create an invoke wrapper which calls the method directly.
4487 */
4488 need_direct_wrapper = TRUE;
4489 }
4490
4491 if (method->string_ctor) {
4492 /* Can't share this as we push a string as this */
4493 need_direct_wrapper = TRUE;
4494 }
4495
4496 return mono_marshal_get_runtime_invoke_full (method, virtual_, need_direct_wrapper);
4497 }
4498
4499 /*
4500 * mono_marshal_get_runtime_invoke_dynamic:
4501 *
4502 * Return a method which can be used to invoke managed methods from native code
4503 * dynamically.
4504 * The signature of the returned method is given by RuntimeInvokeDynamicFunction:
4505 * void runtime_invoke (void *args, MonoObject **exc, void *compiled_method)
4506 * ARGS should point to an architecture specific structure containing
4507 * the arguments and space for the return value.
4508 * The other arguments are the same as for runtime_invoke (), except that
4509 * ARGS should contain the this argument too.
4510 * This wrapper serves the same purpose as the runtime-invoke wrappers, but there
4511 * is only one copy of it, which is useful in full-aot.
4512 */
4513 MonoMethod*
mono_marshal_get_runtime_invoke_dynamic(void)4514 mono_marshal_get_runtime_invoke_dynamic (void)
4515 {
4516 static MonoMethod *method;
4517 MonoMethodSignature *csig;
4518 MonoExceptionClause *clause;
4519 MonoMethodBuilder *mb;
4520 int pos;
4521 char *name;
4522 WrapperInfo *info;
4523
4524 if (method)
4525 return method;
4526
4527 csig = mono_metadata_signature_alloc (mono_defaults.corlib, 4);
4528
4529 csig->ret = &mono_defaults.void_class->byval_arg;
4530 csig->params [0] = &mono_defaults.int_class->byval_arg;
4531 csig->params [1] = &mono_defaults.int_class->byval_arg;
4532 csig->params [2] = &mono_defaults.int_class->byval_arg;
4533 csig->params [3] = &mono_defaults.int_class->byval_arg;
4534
4535 name = g_strdup ("runtime_invoke_dynamic");
4536 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_RUNTIME_INVOKE);
4537 g_free (name);
4538
4539 #ifdef ENABLE_ILGEN
4540 /* allocate local 0 (object) tmp */
4541 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
4542 /* allocate local 1 (object) exc */
4543 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
4544
4545 /* cond set *exc to null */
4546 mono_mb_emit_byte (mb, CEE_LDARG_1);
4547 mono_mb_emit_byte (mb, CEE_BRFALSE_S);
4548 mono_mb_emit_byte (mb, 3);
4549 mono_mb_emit_byte (mb, CEE_LDARG_1);
4550 mono_mb_emit_byte (mb, CEE_LDNULL);
4551 mono_mb_emit_byte (mb, CEE_STIND_REF);
4552
4553 emit_thread_force_interrupt_checkpoint (mb);
4554
4555 mono_mb_emit_byte (mb, CEE_LDARG_0);
4556 mono_mb_emit_byte (mb, CEE_LDARG_2);
4557 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4558 mono_mb_emit_byte (mb, CEE_MONO_DYN_CALL);
4559
4560 pos = mono_mb_emit_branch (mb, CEE_LEAVE);
4561
4562 clause = (MonoExceptionClause *)mono_image_alloc0 (mono_defaults.corlib, sizeof (MonoExceptionClause));
4563 clause->flags = MONO_EXCEPTION_CLAUSE_FILTER;
4564 clause->try_len = mono_mb_get_label (mb);
4565
4566 /* filter code */
4567 clause->data.filter_offset = mono_mb_get_label (mb);
4568
4569 mono_mb_emit_byte (mb, CEE_POP);
4570 mono_mb_emit_byte (mb, CEE_LDARG_1);
4571 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
4572 mono_mb_emit_byte (mb, CEE_PREFIX1);
4573 mono_mb_emit_byte (mb, CEE_CGT_UN);
4574 mono_mb_emit_byte (mb, CEE_PREFIX1);
4575 mono_mb_emit_byte (mb, CEE_ENDFILTER);
4576
4577 clause->handler_offset = mono_mb_get_label (mb);
4578
4579 /* handler code */
4580 /* store exception */
4581 mono_mb_emit_stloc (mb, 1);
4582
4583 mono_mb_emit_byte (mb, CEE_LDARG_1);
4584 mono_mb_emit_ldloc (mb, 1);
4585 mono_mb_emit_byte (mb, CEE_STIND_REF);
4586
4587 mono_mb_emit_byte (mb, CEE_LDNULL);
4588 mono_mb_emit_stloc (mb, 0);
4589
4590 mono_mb_emit_branch (mb, CEE_LEAVE);
4591
4592 clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset;
4593
4594 mono_mb_set_clauses (mb, 1, clause);
4595
4596 /* return result */
4597 mono_mb_patch_branch (mb, pos);
4598 //mono_mb_emit_ldloc (mb, 0);
4599 mono_mb_emit_byte (mb, CEE_RET);
4600 #endif /* ENABLE_ILGEN */
4601
4602 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_RUNTIME_INVOKE_DYNAMIC);
4603
4604 mono_marshal_lock ();
4605 /* double-checked locking */
4606 if (!method)
4607 method = mono_mb_create (mb, csig, 16, info);
4608
4609 mono_marshal_unlock ();
4610
4611 mono_mb_free (mb);
4612
4613 return method;
4614 }
4615
4616 /*
4617 * mono_marshal_get_runtime_invoke_for_sig:
4618 *
4619 * Return a runtime invoke wrapper for a given signature.
4620 */
4621 MonoMethod *
mono_marshal_get_runtime_invoke_for_sig(MonoMethodSignature * sig)4622 mono_marshal_get_runtime_invoke_for_sig (MonoMethodSignature *sig)
4623 {
4624 MonoMethodSignature *csig, *callsig;
4625 MonoMethodBuilder *mb;
4626 MonoImage *image;
4627 GHashTable *cache = NULL;
4628 GHashTable **cache_table = NULL;
4629 MonoMethod *res = NULL;
4630 char *name;
4631 const char *param_names [16];
4632 WrapperInfo *info;
4633
4634 /* A simplified version of mono_marshal_get_runtime_invoke */
4635
4636 image = mono_defaults.corlib;
4637
4638 callsig = mono_marshal_get_runtime_invoke_sig (sig);
4639
4640 cache_table = &image->wrapper_caches.runtime_invoke_sig_cache;
4641
4642 cache = get_cache (cache_table, (GHashFunc)mono_signature_hash,
4643 (GCompareFunc)runtime_invoke_signature_equal);
4644
4645 /* from mono_marshal_find_in_cache */
4646 mono_marshal_lock ();
4647 res = (MonoMethod *)g_hash_table_lookup (cache, callsig);
4648 mono_marshal_unlock ();
4649
4650 if (res) {
4651 g_free (callsig);
4652 return res;
4653 }
4654
4655 /* Make a copy of the signature from the image mempool */
4656 callsig = mono_metadata_signature_dup_full (image, callsig);
4657
4658 csig = mono_metadata_signature_alloc (image, 4);
4659 csig->ret = &mono_defaults.object_class->byval_arg;
4660 csig->params [0] = &mono_defaults.object_class->byval_arg;
4661 csig->params [1] = &mono_defaults.int_class->byval_arg;
4662 csig->params [2] = &mono_defaults.int_class->byval_arg;
4663 csig->params [3] = &mono_defaults.int_class->byval_arg;
4664 csig->pinvoke = 1;
4665 #if TARGET_WIN32
4666 /* This is called from runtime code so it has to be cdecl */
4667 csig->call_convention = MONO_CALL_C;
4668 #endif
4669
4670 name = mono_signature_to_name (callsig, "runtime_invoke_sig");
4671 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_RUNTIME_INVOKE);
4672 g_free (name);
4673
4674 #ifdef ENABLE_ILGEN
4675 param_names [0] = "this";
4676 param_names [1] = "params";
4677 param_names [2] = "exc";
4678 param_names [3] = "method";
4679 mono_mb_set_param_names (mb, param_names);
4680
4681 emit_runtime_invoke_body (mb, image, NULL, sig, callsig, FALSE, FALSE);
4682 #endif
4683
4684 /* taken from mono_mb_create_and_cache */
4685 mono_marshal_lock ();
4686 res = (MonoMethod *)g_hash_table_lookup (cache, callsig);
4687 mono_marshal_unlock ();
4688
4689 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_RUNTIME_INVOKE_NORMAL);
4690 info->d.runtime_invoke.sig = callsig;
4691
4692 /* Somebody may have created it before us */
4693 if (!res) {
4694 MonoMethod *newm;
4695 newm = mono_mb_create (mb, csig, sig->param_count + 16, info);
4696
4697 mono_marshal_lock ();
4698 res = (MonoMethod *)g_hash_table_lookup (cache, callsig);
4699 if (!res) {
4700 res = newm;
4701 g_hash_table_insert (cache, callsig, res);
4702 } else {
4703 mono_free_method (newm);
4704 }
4705 mono_marshal_unlock ();
4706 }
4707
4708 /* end mono_mb_create_and_cache */
4709
4710 mono_mb_free (mb);
4711
4712 return res;
4713 }
4714
4715 #ifdef ENABLE_ILGEN
4716 static void
mono_mb_emit_auto_layout_exception(MonoMethodBuilder * mb,MonoClass * klass)4717 mono_mb_emit_auto_layout_exception (MonoMethodBuilder *mb, MonoClass *klass)
4718 {
4719 char *msg = g_strdup_printf ("The type `%s.%s' layout needs to be Sequential or Explicit",
4720 klass->name_space, klass->name);
4721
4722 mono_mb_emit_exception_marshal_directive (mb, msg);
4723 }
4724 #endif
4725
4726 /**
4727 * mono_marshal_get_icall_wrapper:
4728 * Generates IL code for the icall wrapper. The generated method
4729 * calls the unmanaged code in \p func.
4730 */
4731 MonoMethod *
mono_marshal_get_icall_wrapper(MonoMethodSignature * sig,const char * name,gconstpointer func,gboolean check_exceptions)4732 mono_marshal_get_icall_wrapper (MonoMethodSignature *sig, const char *name, gconstpointer func, gboolean check_exceptions)
4733 {
4734 MonoMethodSignature *csig, *csig2;
4735 MonoMethodBuilder *mb;
4736 MonoMethod *res;
4737 int i;
4738 WrapperInfo *info;
4739
4740 GHashTable *cache = get_cache (&mono_defaults.object_class->image->icall_wrapper_cache, mono_aligned_addr_hash, NULL);
4741 if ((res = mono_marshal_find_in_cache (cache, (gpointer) func)))
4742 return res;
4743
4744 g_assert (sig->pinvoke);
4745
4746 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_MANAGED_TO_NATIVE);
4747
4748 mb->method->save_lmf = 1;
4749
4750 /* Add an explicit this argument */
4751 if (sig->hasthis)
4752 csig2 = mono_metadata_signature_dup_add_this (mono_defaults.corlib, sig, mono_defaults.object_class);
4753 else
4754 csig2 = mono_metadata_signature_dup_full (mono_defaults.corlib, sig);
4755
4756 #ifdef ENABLE_ILGEN
4757 if (sig->hasthis)
4758 mono_mb_emit_byte (mb, CEE_LDARG_0);
4759
4760 for (i = 0; i < sig->param_count; i++)
4761 mono_mb_emit_ldarg (mb, i + sig->hasthis);
4762
4763 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
4764 mono_mb_emit_op (mb, CEE_MONO_JIT_ICALL_ADDR, (gpointer)func);
4765 mono_mb_emit_calli (mb, csig2);
4766 if (check_exceptions)
4767 emit_thread_interrupt_checkpoint (mb);
4768 mono_mb_emit_byte (mb, CEE_RET);
4769 #endif
4770
4771 csig = mono_metadata_signature_dup_full (mono_defaults.corlib, sig);
4772 csig->pinvoke = 0;
4773 if (csig->call_convention == MONO_CALL_VARARG)
4774 csig->call_convention = 0;
4775
4776 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_ICALL_WRAPPER);
4777 info->d.icall.func = (gpointer)func;
4778 res = mono_mb_create_and_cache_full (cache, (gpointer) func, mb, csig, csig->param_count + 16, info, NULL);
4779 mono_mb_free (mb);
4780
4781 return res;
4782 }
4783
4784 static int
emit_marshal_custom(EmitMarshalContext * m,int argnum,MonoType * t,MonoMarshalSpec * spec,int conv_arg,MonoType ** conv_arg_type,MarshalAction action)4785 emit_marshal_custom (EmitMarshalContext *m, int argnum, MonoType *t,
4786 MonoMarshalSpec *spec,
4787 int conv_arg, MonoType **conv_arg_type,
4788 MarshalAction action)
4789 {
4790 #ifndef ENABLE_ILGEN
4791 if (action == MARSHAL_ACTION_CONV_IN && t->type == MONO_TYPE_VALUETYPE)
4792 *conv_arg_type = &mono_defaults.int_class->byval_arg;
4793 return conv_arg;
4794 #else
4795 MonoError error;
4796 MonoType *mtype;
4797 MonoClass *mklass;
4798 static MonoClass *ICustomMarshaler = NULL;
4799 static MonoMethod *cleanup_native, *cleanup_managed;
4800 static MonoMethod *marshal_managed_to_native, *marshal_native_to_managed;
4801 MonoMethod *get_instance = NULL;
4802 MonoMethodBuilder *mb = m->mb;
4803 char *exception_msg = NULL;
4804 guint32 loc1;
4805 int pos2;
4806
4807 if (!ICustomMarshaler) {
4808 MonoClass *klass = mono_class_try_get_icustom_marshaler_class ();
4809 if (!klass) {
4810 exception_msg = g_strdup ("Current profile doesn't support ICustomMarshaler");
4811 goto handle_exception;
4812 }
4813
4814 cleanup_native = mono_class_get_method_from_name (klass, "CleanUpNativeData", 1);
4815 g_assert (cleanup_native);
4816 cleanup_managed = mono_class_get_method_from_name (klass, "CleanUpManagedData", 1);
4817 g_assert (cleanup_managed);
4818 marshal_managed_to_native = mono_class_get_method_from_name (klass, "MarshalManagedToNative", 1);
4819 g_assert (marshal_managed_to_native);
4820 marshal_native_to_managed = mono_class_get_method_from_name (klass, "MarshalNativeToManaged", 1);
4821 g_assert (marshal_native_to_managed);
4822
4823 mono_memory_barrier ();
4824 ICustomMarshaler = klass;
4825 }
4826
4827 if (spec->data.custom_data.image)
4828 mtype = mono_reflection_type_from_name_checked (spec->data.custom_data.custom_name, spec->data.custom_data.image, &error);
4829 else
4830 mtype = mono_reflection_type_from_name_checked (spec->data.custom_data.custom_name, m->image, &error);
4831 g_assert (mtype != NULL);
4832 mono_error_assert_ok (&error);
4833 mklass = mono_class_from_mono_type (mtype);
4834 g_assert (mklass != NULL);
4835
4836 if (!mono_class_is_assignable_from (ICustomMarshaler, mklass))
4837 exception_msg = g_strdup_printf ("Custom marshaler '%s' does not implement the ICustomMarshaler interface.", mklass->name);
4838
4839 get_instance = mono_class_get_method_from_name_flags (mklass, "GetInstance", 1, METHOD_ATTRIBUTE_STATIC);
4840 if (get_instance) {
4841 MonoMethodSignature *get_sig = mono_method_signature (get_instance);
4842 if ((get_sig->ret->type != MONO_TYPE_CLASS) ||
4843 (mono_class_from_mono_type (get_sig->ret) != ICustomMarshaler) ||
4844 (get_sig->params [0]->type != MONO_TYPE_STRING))
4845 get_instance = NULL;
4846 }
4847
4848 if (!get_instance)
4849 exception_msg = g_strdup_printf ("Custom marshaler '%s' does not implement a static GetInstance method that takes a single string parameter and returns an ICustomMarshaler.", mklass->name);
4850
4851 handle_exception:
4852 /* Throw exception and emit compensation code if neccesary */
4853 if (exception_msg) {
4854 switch (action) {
4855 case MARSHAL_ACTION_CONV_IN:
4856 case MARSHAL_ACTION_CONV_RESULT:
4857 case MARSHAL_ACTION_MANAGED_CONV_RESULT:
4858 if ((action == MARSHAL_ACTION_CONV_RESULT) || (action == MARSHAL_ACTION_MANAGED_CONV_RESULT))
4859 mono_mb_emit_byte (mb, CEE_POP);
4860
4861 mono_mb_emit_exception_full (mb, "System", "ApplicationException", exception_msg);
4862
4863 break;
4864 case MARSHAL_ACTION_PUSH:
4865 mono_mb_emit_byte (mb, CEE_LDNULL);
4866 break;
4867 default:
4868 break;
4869 }
4870 return 0;
4871 }
4872
4873 /* FIXME: MS.NET seems to create one instance for each klass + cookie pair */
4874 /* FIXME: MS.NET throws an exception if GetInstance returns null */
4875
4876 switch (action) {
4877 case MARSHAL_ACTION_CONV_IN:
4878 switch (t->type) {
4879 case MONO_TYPE_CLASS:
4880 case MONO_TYPE_OBJECT:
4881 case MONO_TYPE_STRING:
4882 case MONO_TYPE_ARRAY:
4883 case MONO_TYPE_SZARRAY:
4884 case MONO_TYPE_VALUETYPE:
4885 break;
4886
4887 default:
4888 g_warning ("custom marshalling of type %x is currently not supported", t->type);
4889 g_assert_not_reached ();
4890 break;
4891 }
4892
4893 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4894
4895 mono_mb_emit_byte (mb, CEE_LDNULL);
4896 mono_mb_emit_stloc (mb, conv_arg);
4897
4898 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT))
4899 break;
4900
4901 /* Minic MS.NET behavior */
4902 if (!t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT) && !(t->attrs & PARAM_ATTRIBUTE_IN))
4903 break;
4904
4905 /* Check for null */
4906 mono_mb_emit_ldarg (mb, argnum);
4907 if (t->byref)
4908 mono_mb_emit_byte (mb, CEE_LDIND_I);
4909 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
4910
4911 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
4912
4913 mono_mb_emit_op (mb, CEE_CALL, get_instance);
4914
4915 mono_mb_emit_ldarg (mb, argnum);
4916 if (t->byref)
4917 mono_mb_emit_byte (mb, CEE_LDIND_REF);
4918
4919 if (t->type == MONO_TYPE_VALUETYPE) {
4920 /*
4921 * Since we can't determine the type of the argument, we
4922 * will assume the unmanaged function takes a pointer.
4923 */
4924 *conv_arg_type = &mono_defaults.int_class->byval_arg;
4925
4926 mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type (t));
4927 }
4928
4929 mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_managed_to_native);
4930 mono_mb_emit_stloc (mb, conv_arg);
4931
4932 mono_mb_patch_branch (mb, pos2);
4933 break;
4934
4935 case MARSHAL_ACTION_CONV_OUT:
4936 /* Check for null */
4937 mono_mb_emit_ldloc (mb, conv_arg);
4938 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
4939
4940 if (t->byref) {
4941 mono_mb_emit_ldarg (mb, argnum);
4942
4943 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
4944
4945 mono_mb_emit_op (mb, CEE_CALL, get_instance);
4946
4947 mono_mb_emit_ldloc (mb, conv_arg);
4948 mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed);
4949 mono_mb_emit_byte (mb, CEE_STIND_REF);
4950 } else if (t->attrs & PARAM_ATTRIBUTE_OUT) {
4951 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
4952
4953 mono_mb_emit_op (mb, CEE_CALL, get_instance);
4954
4955 mono_mb_emit_ldloc (mb, conv_arg);
4956 mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed);
4957
4958 /* We have nowhere to store the result */
4959 mono_mb_emit_byte (mb, CEE_POP);
4960 }
4961
4962 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
4963
4964 mono_mb_emit_op (mb, CEE_CALL, get_instance);
4965
4966 mono_mb_emit_ldloc (mb, conv_arg);
4967
4968 mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_native);
4969
4970 mono_mb_patch_branch (mb, pos2);
4971 break;
4972
4973 case MARSHAL_ACTION_PUSH:
4974 if (t->byref)
4975 mono_mb_emit_ldloc_addr (mb, conv_arg);
4976 else
4977 mono_mb_emit_ldloc (mb, conv_arg);
4978 break;
4979
4980 case MARSHAL_ACTION_CONV_RESULT:
4981 loc1 = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
4982
4983 mono_mb_emit_stloc (mb, 3);
4984
4985 mono_mb_emit_ldloc (mb, 3);
4986 mono_mb_emit_stloc (mb, loc1);
4987
4988 /* Check for null */
4989 mono_mb_emit_ldloc (mb, 3);
4990 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
4991
4992 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
4993
4994 mono_mb_emit_op (mb, CEE_CALL, get_instance);
4995 mono_mb_emit_byte (mb, CEE_DUP);
4996
4997 mono_mb_emit_ldloc (mb, 3);
4998 mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed);
4999 mono_mb_emit_stloc (mb, 3);
5000
5001 mono_mb_emit_ldloc (mb, loc1);
5002 mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_native);
5003
5004 mono_mb_patch_branch (mb, pos2);
5005 break;
5006
5007 case MARSHAL_ACTION_MANAGED_CONV_IN:
5008 conv_arg = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
5009
5010 mono_mb_emit_byte (mb, CEE_LDNULL);
5011 mono_mb_emit_stloc (mb, conv_arg);
5012
5013 if (t->byref && t->attrs & PARAM_ATTRIBUTE_OUT)
5014 break;
5015
5016 /* Check for null */
5017 mono_mb_emit_ldarg (mb, argnum);
5018 if (t->byref)
5019 mono_mb_emit_byte (mb, CEE_LDIND_I);
5020 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
5021
5022 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
5023 mono_mb_emit_op (mb, CEE_CALL, get_instance);
5024
5025 mono_mb_emit_ldarg (mb, argnum);
5026 if (t->byref)
5027 mono_mb_emit_byte (mb, CEE_LDIND_I);
5028
5029 mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_native_to_managed);
5030 mono_mb_emit_stloc (mb, conv_arg);
5031
5032 mono_mb_patch_branch (mb, pos2);
5033 break;
5034
5035 case MARSHAL_ACTION_MANAGED_CONV_RESULT:
5036 g_assert (!t->byref);
5037
5038 loc1 = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
5039
5040 mono_mb_emit_stloc (mb, 3);
5041
5042 mono_mb_emit_ldloc (mb, 3);
5043 mono_mb_emit_stloc (mb, loc1);
5044
5045 /* Check for null */
5046 mono_mb_emit_ldloc (mb, 3);
5047 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
5048
5049 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
5050 mono_mb_emit_op (mb, CEE_CALL, get_instance);
5051 mono_mb_emit_byte (mb, CEE_DUP);
5052
5053 mono_mb_emit_ldloc (mb, 3);
5054 mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_managed_to_native);
5055 mono_mb_emit_stloc (mb, 3);
5056
5057 mono_mb_emit_ldloc (mb, loc1);
5058 mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_managed);
5059
5060 mono_mb_patch_branch (mb, pos2);
5061 break;
5062
5063 case MARSHAL_ACTION_MANAGED_CONV_OUT:
5064
5065 /* Check for null */
5066 mono_mb_emit_ldloc (mb, conv_arg);
5067 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
5068
5069 if (t->byref) {
5070 mono_mb_emit_ldarg (mb, argnum);
5071
5072 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
5073
5074 mono_mb_emit_op (mb, CEE_CALL, get_instance);
5075
5076 mono_mb_emit_ldloc (mb, conv_arg);
5077 mono_mb_emit_op (mb, CEE_CALLVIRT, marshal_managed_to_native);
5078 mono_mb_emit_byte (mb, CEE_STIND_I);
5079 }
5080
5081 /* Call CleanUpManagedData */
5082 mono_mb_emit_ldstr (mb, g_strdup (spec->data.custom_data.cookie));
5083
5084 mono_mb_emit_op (mb, CEE_CALL, get_instance);
5085
5086 mono_mb_emit_ldloc (mb, conv_arg);
5087 mono_mb_emit_op (mb, CEE_CALLVIRT, cleanup_managed);
5088
5089 mono_mb_patch_branch (mb, pos2);
5090 break;
5091
5092 default:
5093 g_assert_not_reached ();
5094 }
5095 return conv_arg;
5096 #endif
5097
5098 }
5099
5100 static int
emit_marshal_asany(EmitMarshalContext * m,int argnum,MonoType * t,MonoMarshalSpec * spec,int conv_arg,MonoType ** conv_arg_type,MarshalAction action)5101 emit_marshal_asany (EmitMarshalContext *m, int argnum, MonoType *t,
5102 MonoMarshalSpec *spec,
5103 int conv_arg, MonoType **conv_arg_type,
5104 MarshalAction action)
5105 {
5106 #ifdef ENABLE_ILGEN
5107 MonoMethodBuilder *mb = m->mb;
5108
5109 switch (action) {
5110 case MARSHAL_ACTION_CONV_IN: {
5111 MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, NULL);
5112
5113 g_assert (t->type == MONO_TYPE_OBJECT);
5114 g_assert (!t->byref);
5115
5116 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5117 mono_mb_emit_ldarg (mb, argnum);
5118 mono_mb_emit_icon (mb, encoding);
5119 mono_mb_emit_icon (mb, t->attrs);
5120 mono_mb_emit_icall (mb, mono_marshal_asany);
5121 mono_mb_emit_stloc (mb, conv_arg);
5122 break;
5123 }
5124
5125 case MARSHAL_ACTION_PUSH:
5126 mono_mb_emit_ldloc (mb, conv_arg);
5127 break;
5128
5129 case MARSHAL_ACTION_CONV_OUT: {
5130 MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, NULL);
5131
5132 mono_mb_emit_ldarg (mb, argnum);
5133 mono_mb_emit_ldloc (mb, conv_arg);
5134 mono_mb_emit_icon (mb, encoding);
5135 mono_mb_emit_icon (mb, t->attrs);
5136 mono_mb_emit_icall (mb, mono_marshal_free_asany);
5137 break;
5138 }
5139
5140 default:
5141 g_assert_not_reached ();
5142 }
5143 #endif
5144 return conv_arg;
5145 }
5146
5147 static int
emit_marshal_vtype(EmitMarshalContext * m,int argnum,MonoType * t,MonoMarshalSpec * spec,int conv_arg,MonoType ** conv_arg_type,MarshalAction action)5148 emit_marshal_vtype (EmitMarshalContext *m, int argnum, MonoType *t,
5149 MonoMarshalSpec *spec,
5150 int conv_arg, MonoType **conv_arg_type,
5151 MarshalAction action)
5152 {
5153 #ifdef ENABLE_ILGEN
5154 MonoMethodBuilder *mb = m->mb;
5155 MonoClass *klass, *date_time_class;
5156 int pos = 0, pos2;
5157
5158 klass = mono_class_from_mono_type (t);
5159
5160 date_time_class = mono_class_get_date_time_class ();
5161
5162 switch (action) {
5163 case MARSHAL_ACTION_CONV_IN:
5164 if (klass == date_time_class) {
5165 /* Convert it to an OLE DATE type */
5166 static MonoMethod *to_oadate;
5167
5168 if (!to_oadate)
5169 to_oadate = mono_class_get_method_from_name (date_time_class, "ToOADate", 0);
5170 g_assert (to_oadate);
5171
5172 conv_arg = mono_mb_add_local (mb, &mono_defaults.double_class->byval_arg);
5173
5174 if (t->byref) {
5175 mono_mb_emit_ldarg (mb, argnum);
5176 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
5177 }
5178
5179 if (!(t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN) && (t->attrs & PARAM_ATTRIBUTE_OUT))) {
5180 if (!t->byref)
5181 m->csig->params [argnum - m->csig->hasthis] = &mono_defaults.double_class->byval_arg;
5182
5183 mono_mb_emit_ldarg_addr (mb, argnum);
5184 mono_mb_emit_managed_call (mb, to_oadate, NULL);
5185 mono_mb_emit_stloc (mb, conv_arg);
5186 }
5187
5188 if (t->byref)
5189 mono_mb_patch_branch (mb, pos);
5190 break;
5191 }
5192
5193 if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype)
5194 break;
5195
5196 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5197
5198 /* store the address of the source into local variable 0 */
5199 if (t->byref)
5200 mono_mb_emit_ldarg (mb, argnum);
5201 else
5202 mono_mb_emit_ldarg_addr (mb, argnum);
5203
5204 mono_mb_emit_stloc (mb, 0);
5205
5206 /* allocate space for the native struct and
5207 * store the address into local variable 1 (dest) */
5208 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
5209 mono_mb_emit_byte (mb, CEE_PREFIX1);
5210 mono_mb_emit_byte (mb, CEE_LOCALLOC);
5211 mono_mb_emit_stloc (mb, conv_arg);
5212
5213 if (t->byref) {
5214 mono_mb_emit_ldloc (mb, 0);
5215 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
5216 }
5217
5218 if (!(t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN) && (t->attrs & PARAM_ATTRIBUTE_OUT))) {
5219 /* set dst_ptr */
5220 mono_mb_emit_ldloc (mb, conv_arg);
5221 mono_mb_emit_stloc (mb, 1);
5222
5223 /* emit valuetype conversion code */
5224 emit_struct_conv (mb, klass, FALSE);
5225 }
5226
5227 if (t->byref)
5228 mono_mb_patch_branch (mb, pos);
5229 break;
5230
5231 case MARSHAL_ACTION_PUSH:
5232 if (spec && spec->native == MONO_NATIVE_LPSTRUCT) {
5233 /* FIXME: */
5234 g_assert (!t->byref);
5235
5236 /* Have to change the signature since the vtype is passed byref */
5237 m->csig->params [argnum - m->csig->hasthis] = &mono_defaults.int_class->byval_arg;
5238
5239 if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype)
5240 mono_mb_emit_ldarg_addr (mb, argnum);
5241 else
5242 mono_mb_emit_ldloc (mb, conv_arg);
5243 break;
5244 }
5245
5246 if (klass == date_time_class) {
5247 if (t->byref)
5248 mono_mb_emit_ldloc_addr (mb, conv_arg);
5249 else
5250 mono_mb_emit_ldloc (mb, conv_arg);
5251 break;
5252 }
5253
5254 if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype) {
5255 mono_mb_emit_ldarg (mb, argnum);
5256 break;
5257 }
5258 mono_mb_emit_ldloc (mb, conv_arg);
5259 if (!t->byref) {
5260 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5261 mono_mb_emit_op (mb, CEE_MONO_LDNATIVEOBJ, klass);
5262 }
5263 break;
5264
5265 case MARSHAL_ACTION_CONV_OUT:
5266 if (klass == date_time_class) {
5267 /* Convert from an OLE DATE type */
5268 static MonoMethod *from_oadate;
5269
5270 if (!t->byref)
5271 break;
5272
5273 if (!((t->attrs & PARAM_ATTRIBUTE_IN) && !(t->attrs & PARAM_ATTRIBUTE_OUT))) {
5274 if (!from_oadate)
5275 from_oadate = mono_class_get_method_from_name (date_time_class, "FromOADate", 1);
5276 g_assert (from_oadate);
5277
5278 mono_mb_emit_ldarg (mb, argnum);
5279 mono_mb_emit_ldloc (mb, conv_arg);
5280 mono_mb_emit_managed_call (mb, from_oadate, NULL);
5281 mono_mb_emit_op (mb, CEE_STOBJ, date_time_class);
5282 }
5283 break;
5284 }
5285
5286 if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype)
5287 break;
5288
5289 if (t->byref) {
5290 /* dst = argument */
5291 mono_mb_emit_ldarg (mb, argnum);
5292 mono_mb_emit_stloc (mb, 1);
5293
5294 mono_mb_emit_ldloc (mb, 1);
5295 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
5296
5297 if (!((t->attrs & PARAM_ATTRIBUTE_IN) && !(t->attrs & PARAM_ATTRIBUTE_OUT))) {
5298 /* src = tmp_locals [i] */
5299 mono_mb_emit_ldloc (mb, conv_arg);
5300 mono_mb_emit_stloc (mb, 0);
5301
5302 /* emit valuetype conversion code */
5303 emit_struct_conv (mb, klass, TRUE);
5304 }
5305 }
5306
5307 emit_struct_free (mb, klass, conv_arg);
5308
5309 if (t->byref)
5310 mono_mb_patch_branch (mb, pos);
5311 break;
5312
5313 case MARSHAL_ACTION_CONV_RESULT:
5314 if (mono_class_is_explicit_layout (klass) || klass->blittable) {
5315 mono_mb_emit_stloc (mb, 3);
5316 break;
5317 }
5318
5319 /* load pointer to returned value type */
5320 g_assert (m->vtaddr_var);
5321 mono_mb_emit_ldloc (mb, m->vtaddr_var);
5322 /* store the address of the source into local variable 0 */
5323 mono_mb_emit_stloc (mb, 0);
5324 /* set dst_ptr */
5325 mono_mb_emit_ldloc_addr (mb, 3);
5326 mono_mb_emit_stloc (mb, 1);
5327
5328 /* emit valuetype conversion code */
5329 emit_struct_conv (mb, klass, TRUE);
5330 break;
5331
5332 case MARSHAL_ACTION_MANAGED_CONV_IN:
5333 if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype) {
5334 conv_arg = 0;
5335 break;
5336 }
5337
5338 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
5339
5340 if (t->attrs & PARAM_ATTRIBUTE_OUT)
5341 break;
5342
5343 if (t->byref)
5344 mono_mb_emit_ldarg (mb, argnum);
5345 else
5346 mono_mb_emit_ldarg_addr (mb, argnum);
5347 mono_mb_emit_stloc (mb, 0);
5348
5349 if (t->byref) {
5350 mono_mb_emit_ldloc (mb, 0);
5351 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
5352 }
5353
5354 mono_mb_emit_ldloc_addr (mb, conv_arg);
5355 mono_mb_emit_stloc (mb, 1);
5356
5357 /* emit valuetype conversion code */
5358 emit_struct_conv (mb, klass, TRUE);
5359
5360 if (t->byref)
5361 mono_mb_patch_branch (mb, pos);
5362 break;
5363
5364 case MARSHAL_ACTION_MANAGED_CONV_OUT:
5365 if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype)
5366 break;
5367 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_IN) && !(t->attrs & PARAM_ATTRIBUTE_OUT))
5368 break;
5369
5370 /* Check for null */
5371 mono_mb_emit_ldarg (mb, argnum);
5372 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
5373
5374 /* Set src */
5375 mono_mb_emit_ldloc_addr (mb, conv_arg);
5376 mono_mb_emit_stloc (mb, 0);
5377
5378 /* Set dest */
5379 mono_mb_emit_ldarg (mb, argnum);
5380 mono_mb_emit_stloc (mb, 1);
5381
5382 /* emit valuetype conversion code */
5383 emit_struct_conv (mb, klass, FALSE);
5384
5385 mono_mb_patch_branch (mb, pos2);
5386 break;
5387
5388 case MARSHAL_ACTION_MANAGED_CONV_RESULT:
5389 if (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype) {
5390 mono_mb_emit_stloc (mb, 3);
5391 m->retobj_var = 0;
5392 break;
5393 }
5394
5395 /* load pointer to returned value type */
5396 g_assert (m->vtaddr_var);
5397 mono_mb_emit_ldloc (mb, m->vtaddr_var);
5398
5399 /* store the address of the source into local variable 0 */
5400 mono_mb_emit_stloc (mb, 0);
5401 /* allocate space for the native struct and
5402 * store the address into dst_ptr */
5403 m->retobj_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5404 m->retobj_class = klass;
5405 g_assert (m->retobj_var);
5406 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
5407 mono_mb_emit_byte (mb, CEE_CONV_I);
5408 mono_mb_emit_icall (mb, ves_icall_marshal_alloc);
5409 mono_mb_emit_stloc (mb, 1);
5410 mono_mb_emit_ldloc (mb, 1);
5411 mono_mb_emit_stloc (mb, m->retobj_var);
5412
5413 /* emit valuetype conversion code */
5414 emit_struct_conv (mb, klass, FALSE);
5415 break;
5416
5417 default:
5418 g_assert_not_reached ();
5419 }
5420 #endif
5421 return conv_arg;
5422 }
5423
5424 static int
emit_marshal_string(EmitMarshalContext * m,int argnum,MonoType * t,MonoMarshalSpec * spec,int conv_arg,MonoType ** conv_arg_type,MarshalAction action)5425 emit_marshal_string (EmitMarshalContext *m, int argnum, MonoType *t,
5426 MonoMarshalSpec *spec,
5427 int conv_arg, MonoType **conv_arg_type,
5428 MarshalAction action)
5429 {
5430 #ifndef ENABLE_ILGEN
5431 switch (action) {
5432 case MARSHAL_ACTION_CONV_IN:
5433 *conv_arg_type = &mono_defaults.int_class->byval_arg;
5434 break;
5435 case MARSHAL_ACTION_MANAGED_CONV_IN:
5436 *conv_arg_type = &mono_defaults.int_class->byval_arg;
5437 break;
5438 }
5439 #else
5440 MonoMethodBuilder *mb = m->mb;
5441 MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
5442 MonoMarshalConv conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec);
5443 gboolean need_free;
5444
5445 switch (action) {
5446 case MARSHAL_ACTION_CONV_IN:
5447 *conv_arg_type = &mono_defaults.int_class->byval_arg;
5448 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5449
5450 if (t->byref) {
5451 if (t->attrs & PARAM_ATTRIBUTE_OUT)
5452 break;
5453
5454 mono_mb_emit_ldarg (mb, argnum);
5455 mono_mb_emit_byte (mb, CEE_LDIND_I);
5456 } else {
5457 mono_mb_emit_ldarg (mb, argnum);
5458 }
5459
5460 if (conv == MONO_MARSHAL_CONV_INVALID) {
5461 char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
5462 mono_mb_emit_exception_marshal_directive (mb, msg);
5463 } else {
5464 mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
5465
5466 mono_mb_emit_stloc (mb, conv_arg);
5467 }
5468 break;
5469
5470 case MARSHAL_ACTION_CONV_OUT:
5471 conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
5472 if (conv == MONO_MARSHAL_CONV_INVALID) {
5473 char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
5474 mono_mb_emit_exception_marshal_directive (mb, msg);
5475 break;
5476 }
5477
5478 if (encoding == MONO_NATIVE_VBBYREFSTR) {
5479 static MonoMethod *m;
5480
5481 if (!m) {
5482 m = mono_class_get_method_from_name_flags (mono_defaults.string_class, "get_Length", -1, 0);
5483 g_assert (m);
5484 }
5485
5486 if (!t->byref) {
5487 char *msg = g_strdup_printf ("VBByRefStr marshalling requires a ref parameter.", encoding);
5488 mono_mb_emit_exception_marshal_directive (mb, msg);
5489 break;
5490 }
5491
5492 /*
5493 * Have to allocate a new string with the same length as the original, and
5494 * copy the contents of the buffer pointed to by CONV_ARG into it.
5495 */
5496 g_assert (t->byref);
5497 mono_mb_emit_ldarg (mb, argnum);
5498 mono_mb_emit_ldloc (mb, conv_arg);
5499 mono_mb_emit_ldarg (mb, argnum);
5500 mono_mb_emit_byte (mb, CEE_LDIND_I);
5501 mono_mb_emit_managed_call (mb, m, NULL);
5502 mono_mb_emit_icall (mb, mono_string_new_len_wrapper);
5503 mono_mb_emit_byte (mb, CEE_STIND_REF);
5504 } else if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) {
5505 int stind_op;
5506 mono_mb_emit_ldarg (mb, argnum);
5507 mono_mb_emit_ldloc (mb, conv_arg);
5508 mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
5509 mono_mb_emit_byte (mb, stind_op);
5510 need_free = TRUE;
5511 }
5512
5513 if (need_free) {
5514 mono_mb_emit_ldloc (mb, conv_arg);
5515 if (conv == MONO_MARSHAL_CONV_BSTR_STR)
5516 mono_mb_emit_icall (mb, mono_free_bstr);
5517 else
5518 mono_mb_emit_icall (mb, mono_marshal_free);
5519 }
5520 break;
5521
5522 case MARSHAL_ACTION_PUSH:
5523 if (t->byref && encoding != MONO_NATIVE_VBBYREFSTR)
5524 mono_mb_emit_ldloc_addr (mb, conv_arg);
5525 else
5526 mono_mb_emit_ldloc (mb, conv_arg);
5527 break;
5528
5529 case MARSHAL_ACTION_CONV_RESULT:
5530 mono_mb_emit_stloc (mb, 0);
5531
5532 conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
5533 if (conv == MONO_MARSHAL_CONV_INVALID) {
5534 char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
5535 mono_mb_emit_exception_marshal_directive (mb, msg);
5536 break;
5537 }
5538
5539 mono_mb_emit_ldloc (mb, 0);
5540 mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
5541 mono_mb_emit_stloc (mb, 3);
5542
5543 /* free the string */
5544 mono_mb_emit_ldloc (mb, 0);
5545 if (conv == MONO_MARSHAL_CONV_BSTR_STR)
5546 mono_mb_emit_icall (mb, mono_free_bstr);
5547 else
5548 mono_mb_emit_icall (mb, mono_marshal_free);
5549 break;
5550
5551 case MARSHAL_ACTION_MANAGED_CONV_IN:
5552 conv_arg = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
5553
5554 *conv_arg_type = &mono_defaults.int_class->byval_arg;
5555
5556 if (t->byref) {
5557 if (t->attrs & PARAM_ATTRIBUTE_OUT)
5558 break;
5559 }
5560
5561 conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
5562 if (conv == MONO_MARSHAL_CONV_INVALID) {
5563 char *msg = g_strdup_printf ("string marshalling conversion %d not implemented", encoding);
5564 mono_mb_emit_exception_marshal_directive (mb, msg);
5565 break;
5566 }
5567
5568 mono_mb_emit_ldarg (mb, argnum);
5569 if (t->byref)
5570 mono_mb_emit_byte (mb, CEE_LDIND_I);
5571 mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
5572 mono_mb_emit_stloc (mb, conv_arg);
5573 break;
5574
5575 case MARSHAL_ACTION_MANAGED_CONV_OUT:
5576 if (t->byref) {
5577 if (conv_arg) {
5578 int stind_op;
5579 mono_mb_emit_ldarg (mb, argnum);
5580 mono_mb_emit_ldloc (mb, conv_arg);
5581 mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
5582 mono_mb_emit_byte (mb, stind_op);
5583 }
5584 }
5585 break;
5586
5587 case MARSHAL_ACTION_MANAGED_CONV_RESULT:
5588 if (conv_to_icall (conv, NULL) == mono_marshal_string_to_utf16)
5589 /* We need to make a copy so the caller is able to free it */
5590 mono_mb_emit_icall (mb, mono_marshal_string_to_utf16_copy);
5591 else
5592 mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
5593 mono_mb_emit_stloc (mb, 3);
5594 break;
5595
5596 default:
5597 g_assert_not_reached ();
5598 }
5599 #endif
5600 return conv_arg;
5601 }
5602
5603
5604 static int
emit_marshal_safehandle(EmitMarshalContext * m,int argnum,MonoType * t,MonoMarshalSpec * spec,int conv_arg,MonoType ** conv_arg_type,MarshalAction action)5605 emit_marshal_safehandle (EmitMarshalContext *m, int argnum, MonoType *t,
5606 MonoMarshalSpec *spec, int conv_arg,
5607 MonoType **conv_arg_type, MarshalAction action)
5608 {
5609 #ifndef ENABLE_ILGEN
5610 if (action == MARSHAL_ACTION_CONV_IN)
5611 *conv_arg_type = &mono_defaults.int_class->byval_arg;
5612 #else
5613 MonoMethodBuilder *mb = m->mb;
5614
5615 switch (action){
5616 case MARSHAL_ACTION_CONV_IN: {
5617 MonoType *intptr_type;
5618 int dar_release_slot, pos;
5619
5620 intptr_type = &mono_defaults.int_class->byval_arg;
5621 conv_arg = mono_mb_add_local (mb, intptr_type);
5622 *conv_arg_type = intptr_type;
5623
5624 if (!sh_dangerous_add_ref)
5625 init_safe_handle ();
5626
5627 mono_mb_emit_ldarg (mb, argnum);
5628 pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
5629 mono_mb_emit_exception (mb, "ArgumentNullException", NULL);
5630
5631 mono_mb_patch_branch (mb, pos);
5632 if (t->byref){
5633 /*
5634 * My tests in show that ref SafeHandles are not really
5635 * passed as ref objects. Instead a NULL is passed as the
5636 * value of the ref
5637 */
5638 mono_mb_emit_icon (mb, 0);
5639 mono_mb_emit_stloc (mb, conv_arg);
5640 break;
5641 }
5642
5643 /* Create local to hold the ref parameter to DangerousAddRef */
5644 dar_release_slot = mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
5645
5646 /* set release = false; */
5647 mono_mb_emit_icon (mb, 0);
5648 mono_mb_emit_stloc (mb, dar_release_slot);
5649
5650 /* safehandle.DangerousAddRef (ref release) */
5651 mono_mb_emit_ldarg (mb, argnum);
5652 mono_mb_emit_ldloc_addr (mb, dar_release_slot);
5653 mono_mb_emit_managed_call (mb, sh_dangerous_add_ref, NULL);
5654
5655 /* Pull the handle field from SafeHandle */
5656 mono_mb_emit_ldarg (mb, argnum);
5657 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoSafeHandle, handle));
5658 mono_mb_emit_byte (mb, CEE_LDIND_I);
5659 mono_mb_emit_stloc (mb, conv_arg);
5660
5661 break;
5662 }
5663
5664 case MARSHAL_ACTION_PUSH:
5665 if (t->byref)
5666 mono_mb_emit_ldloc_addr (mb, conv_arg);
5667 else
5668 mono_mb_emit_ldloc (mb, conv_arg);
5669 break;
5670
5671 case MARSHAL_ACTION_CONV_OUT: {
5672 /* The slot for the boolean is the next temporary created after conv_arg, see the CONV_IN code */
5673 int dar_release_slot = conv_arg + 1;
5674 int label_next;
5675
5676 if (!sh_dangerous_release)
5677 init_safe_handle ();
5678
5679 if (t->byref){
5680 MonoMethod *ctor;
5681
5682 /*
5683 * My tests indicate that ref SafeHandles parameters are not actually
5684 * passed by ref, but instead a new Handle is created regardless of
5685 * whether a change happens in the unmanaged side.
5686 *
5687 * Also, the Handle is created before calling into unmanaged code,
5688 * but we do not support that mechanism (getting to the original
5689 * handle) and it makes no difference where we create this
5690 */
5691 ctor = mono_class_get_method_from_name (t->data.klass, ".ctor", 0);
5692 if (ctor == NULL){
5693 mono_mb_emit_exception (mb, "MissingMethodException", "paramterless constructor required");
5694 break;
5695 }
5696 /* refval = new SafeHandleDerived ()*/
5697 mono_mb_emit_ldarg (mb, argnum);
5698 mono_mb_emit_op (mb, CEE_NEWOBJ, ctor);
5699 mono_mb_emit_byte (mb, CEE_STIND_REF);
5700
5701 /* refval.handle = returned_handle */
5702 mono_mb_emit_ldarg (mb, argnum);
5703 mono_mb_emit_byte (mb, CEE_LDIND_REF);
5704 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoSafeHandle, handle));
5705 mono_mb_emit_ldloc (mb, conv_arg);
5706 mono_mb_emit_byte (mb, CEE_STIND_I);
5707 } else {
5708 mono_mb_emit_ldloc (mb, dar_release_slot);
5709 label_next = mono_mb_emit_branch (mb, CEE_BRFALSE);
5710 mono_mb_emit_ldarg (mb, argnum);
5711 mono_mb_emit_managed_call (mb, sh_dangerous_release, NULL);
5712 mono_mb_patch_branch (mb, label_next);
5713 }
5714 break;
5715 }
5716
5717 case MARSHAL_ACTION_CONV_RESULT: {
5718 MonoMethod *ctor = NULL;
5719 int intptr_handle_slot;
5720
5721 if (mono_class_is_abstract (t->data.klass)) {
5722 mono_mb_emit_byte (mb, CEE_POP);
5723 mono_mb_emit_exception_marshal_directive (mb, g_strdup ("Returned SafeHandles should not be abstract"));
5724 break;
5725 }
5726
5727 ctor = mono_class_get_method_from_name (t->data.klass, ".ctor", 0);
5728 if (ctor == NULL){
5729 mono_mb_emit_byte (mb, CEE_POP);
5730 mono_mb_emit_exception (mb, "MissingMethodException", "paramterless constructor required");
5731 break;
5732 }
5733 /* Store the IntPtr results into a local */
5734 intptr_handle_slot = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5735 mono_mb_emit_stloc (mb, intptr_handle_slot);
5736
5737 /* Create return value */
5738 mono_mb_emit_op (mb, CEE_NEWOBJ, ctor);
5739 mono_mb_emit_stloc (mb, 3);
5740
5741 /* Set the return.handle to the value, am using ldflda, not sure if thats a good idea */
5742 mono_mb_emit_ldloc (mb, 3);
5743 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoSafeHandle, handle));
5744 mono_mb_emit_ldloc (mb, intptr_handle_slot);
5745 mono_mb_emit_byte (mb, CEE_STIND_I);
5746 break;
5747 }
5748
5749 case MARSHAL_ACTION_MANAGED_CONV_IN:
5750 fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n");
5751 break;
5752
5753 case MARSHAL_ACTION_MANAGED_CONV_OUT:
5754 fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n");
5755 break;
5756
5757 case MARSHAL_ACTION_MANAGED_CONV_RESULT:
5758 fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n");
5759 break;
5760 default:
5761 printf ("Unhandled case for MarshalAction: %d\n", action);
5762 }
5763 #endif
5764 return conv_arg;
5765 }
5766
5767
5768 static int
emit_marshal_handleref(EmitMarshalContext * m,int argnum,MonoType * t,MonoMarshalSpec * spec,int conv_arg,MonoType ** conv_arg_type,MarshalAction action)5769 emit_marshal_handleref (EmitMarshalContext *m, int argnum, MonoType *t,
5770 MonoMarshalSpec *spec, int conv_arg,
5771 MonoType **conv_arg_type, MarshalAction action)
5772 {
5773 #ifndef ENABLE_ILGEN
5774 if (action == MARSHAL_ACTION_CONV_IN)
5775 *conv_arg_type = &mono_defaults.int_class->byval_arg;
5776 #else
5777 MonoMethodBuilder *mb = m->mb;
5778
5779 switch (action){
5780 case MARSHAL_ACTION_CONV_IN: {
5781 MonoType *intptr_type;
5782
5783 intptr_type = &mono_defaults.int_class->byval_arg;
5784 conv_arg = mono_mb_add_local (mb, intptr_type);
5785 *conv_arg_type = intptr_type;
5786
5787 if (t->byref){
5788 char *msg = g_strdup ("HandleRefs can not be returned from unmanaged code (or passed by ref)");
5789 mono_mb_emit_exception_marshal_directive (mb, msg);
5790 break;
5791 }
5792 mono_mb_emit_ldarg_addr (mb, argnum);
5793 mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoHandleRef, handle));
5794 mono_mb_emit_byte (mb, CEE_ADD);
5795 mono_mb_emit_byte (mb, CEE_LDIND_I);
5796 mono_mb_emit_stloc (mb, conv_arg);
5797 break;
5798 }
5799
5800 case MARSHAL_ACTION_PUSH:
5801 mono_mb_emit_ldloc (mb, conv_arg);
5802 break;
5803
5804 case MARSHAL_ACTION_CONV_OUT: {
5805 /* no resource release required */
5806 break;
5807 }
5808
5809 case MARSHAL_ACTION_CONV_RESULT: {
5810 char *msg = g_strdup ("HandleRefs can not be returned from unmanaged code (or passed by ref)");
5811 mono_mb_emit_exception_marshal_directive (mb, msg);
5812 break;
5813 }
5814
5815 case MARSHAL_ACTION_MANAGED_CONV_IN:
5816 fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_IN\n");
5817 break;
5818
5819 case MARSHAL_ACTION_MANAGED_CONV_OUT:
5820 fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_OUT\n");
5821 break;
5822
5823 case MARSHAL_ACTION_MANAGED_CONV_RESULT:
5824 fprintf (stderr, "mono/marshal: SafeHandles missing MANAGED_CONV_RESULT\n");
5825 break;
5826 default:
5827 fprintf (stderr, "Unhandled case for MarshalAction: %d\n", action);
5828 }
5829 #endif
5830 return conv_arg;
5831 }
5832
5833
5834 static int
emit_marshal_object(EmitMarshalContext * m,int argnum,MonoType * t,MonoMarshalSpec * spec,int conv_arg,MonoType ** conv_arg_type,MarshalAction action)5835 emit_marshal_object (EmitMarshalContext *m, int argnum, MonoType *t,
5836 MonoMarshalSpec *spec,
5837 int conv_arg, MonoType **conv_arg_type,
5838 MarshalAction action)
5839 {
5840 #ifndef ENABLE_ILGEN
5841 if (action == MARSHAL_ACTION_CONV_IN)
5842 *conv_arg_type = &mono_defaults.int_class->byval_arg;
5843 #else
5844 MonoMethodBuilder *mb = m->mb;
5845 MonoClass *klass = mono_class_from_mono_type (t);
5846 int pos, pos2, loc;
5847
5848 switch (action) {
5849 case MARSHAL_ACTION_CONV_IN:
5850 *conv_arg_type = &mono_defaults.int_class->byval_arg;
5851 conv_arg = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5852
5853 m->orig_conv_args [argnum] = 0;
5854
5855 if (mono_class_from_mono_type (t) == mono_defaults.object_class) {
5856 char *msg = g_strdup_printf ("Marshalling of type object is not implemented");
5857 mono_mb_emit_exception_marshal_directive (mb, msg);
5858 break;
5859 }
5860
5861 if (klass->delegate) {
5862 if (t->byref) {
5863 if (!(t->attrs & PARAM_ATTRIBUTE_OUT)) {
5864 char *msg = g_strdup_printf ("Byref marshalling of delegates is not implemented.");
5865 mono_mb_emit_exception_marshal_directive (mb, msg);
5866 }
5867 mono_mb_emit_byte (mb, CEE_LDNULL);
5868 mono_mb_emit_stloc (mb, conv_arg);
5869 } else {
5870 mono_mb_emit_ldarg (mb, argnum);
5871 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, NULL));
5872 mono_mb_emit_stloc (mb, conv_arg);
5873 }
5874 } else if (klass == mono_defaults.stringbuilder_class) {
5875 MonoMarshalNative encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
5876 MonoMarshalConv conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
5877
5878 #if 0
5879 if (t->byref) {
5880 if (!(t->attrs & PARAM_ATTRIBUTE_OUT)) {
5881 char *msg = g_strdup_printf ("Byref marshalling of stringbuilders is not implemented.");
5882 mono_mb_emit_exception_marshal_directive (mb, msg);
5883 }
5884 break;
5885 }
5886 #endif
5887
5888 if (t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN) && (t->attrs & PARAM_ATTRIBUTE_OUT))
5889 break;
5890
5891 if (conv == MONO_MARSHAL_CONV_INVALID) {
5892 char *msg = g_strdup_printf ("stringbuilder marshalling conversion %d not implemented", encoding);
5893 mono_mb_emit_exception_marshal_directive (mb, msg);
5894 break;
5895 }
5896
5897 mono_mb_emit_ldarg (mb, argnum);
5898 if (t->byref)
5899 mono_mb_emit_byte (mb, CEE_LDIND_I);
5900
5901 mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
5902 mono_mb_emit_stloc (mb, conv_arg);
5903 } else if (klass->blittable) {
5904 mono_mb_emit_byte (mb, CEE_LDNULL);
5905 mono_mb_emit_stloc (mb, conv_arg);
5906
5907 mono_mb_emit_ldarg (mb, argnum);
5908 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
5909
5910 mono_mb_emit_ldarg (mb, argnum);
5911 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
5912 mono_mb_emit_stloc (mb, conv_arg);
5913
5914 mono_mb_patch_branch (mb, pos);
5915 break;
5916 } else {
5917 mono_mb_emit_byte (mb, CEE_LDNULL);
5918 mono_mb_emit_stloc (mb, conv_arg);
5919
5920 if (t->byref) {
5921 /* we dont need any conversions for out parameters */
5922 if (t->attrs & PARAM_ATTRIBUTE_OUT)
5923 break;
5924
5925 mono_mb_emit_ldarg (mb, argnum);
5926 mono_mb_emit_byte (mb, CEE_LDIND_I);
5927
5928 } else {
5929 mono_mb_emit_ldarg (mb, argnum);
5930 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
5931 mono_mb_emit_byte (mb, CEE_MONO_OBJADDR);
5932 }
5933
5934 /* store the address of the source into local variable 0 */
5935 mono_mb_emit_stloc (mb, 0);
5936 mono_mb_emit_ldloc (mb, 0);
5937 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
5938
5939 /* allocate space for the native struct and store the address */
5940 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
5941 mono_mb_emit_byte (mb, CEE_PREFIX1);
5942 mono_mb_emit_byte (mb, CEE_LOCALLOC);
5943 mono_mb_emit_stloc (mb, conv_arg);
5944
5945 if (t->byref) {
5946 /* Need to store the original buffer so we can free it later */
5947 m->orig_conv_args [argnum] = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
5948 mono_mb_emit_ldloc (mb, conv_arg);
5949 mono_mb_emit_stloc (mb, m->orig_conv_args [argnum]);
5950 }
5951
5952 /* set the src_ptr */
5953 mono_mb_emit_ldloc (mb, 0);
5954 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
5955 mono_mb_emit_stloc (mb, 0);
5956
5957 /* set dst_ptr */
5958 mono_mb_emit_ldloc (mb, conv_arg);
5959 mono_mb_emit_stloc (mb, 1);
5960
5961 /* emit valuetype conversion code */
5962 emit_struct_conv (mb, klass, FALSE);
5963
5964 mono_mb_patch_branch (mb, pos);
5965 }
5966 break;
5967
5968 case MARSHAL_ACTION_CONV_OUT:
5969 if (klass == mono_defaults.stringbuilder_class) {
5970 gboolean need_free;
5971 MonoMarshalNative encoding;
5972 MonoMarshalConv conv;
5973
5974 encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
5975 conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free);
5976
5977 g_assert (encoding != -1);
5978
5979 if (t->byref) {
5980 //g_assert (!(t->attrs & PARAM_ATTRIBUTE_OUT));
5981
5982 need_free = TRUE;
5983
5984 mono_mb_emit_ldarg (mb, argnum);
5985 mono_mb_emit_ldloc (mb, conv_arg);
5986
5987 switch (encoding) {
5988 case MONO_NATIVE_LPWSTR:
5989 mono_mb_emit_icall (mb, mono_string_utf16_to_builder2);
5990 break;
5991 case MONO_NATIVE_LPSTR:
5992 mono_mb_emit_icall (mb, mono_string_utf8_to_builder2);
5993 break;
5994 case MONO_NATIVE_UTF8STR:
5995 mono_mb_emit_icall (mb, mono_string_utf8_to_builder2);
5996 break;
5997 default:
5998 g_assert_not_reached ();
5999 }
6000
6001 mono_mb_emit_byte (mb, CEE_STIND_REF);
6002 } else {
6003 mono_mb_emit_ldarg (mb, argnum);
6004 mono_mb_emit_ldloc (mb, conv_arg);
6005
6006 mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
6007 }
6008
6009 if (need_free) {
6010 mono_mb_emit_ldloc (mb, conv_arg);
6011 mono_mb_emit_icall (mb, mono_marshal_free);
6012 }
6013 break;
6014 }
6015
6016 if (klass->delegate) {
6017 if (t->byref) {
6018 mono_mb_emit_ldarg (mb, argnum);
6019 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6020 mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
6021 mono_mb_emit_ldloc (mb, conv_arg);
6022 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL));
6023 mono_mb_emit_byte (mb, CEE_STIND_REF);
6024 }
6025 break;
6026 }
6027
6028 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT)) {
6029 /* allocate a new object */
6030 mono_mb_emit_ldarg (mb, argnum);
6031 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6032 mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass);
6033 mono_mb_emit_byte (mb, CEE_STIND_REF);
6034 }
6035
6036 /* dst = *argument */
6037 mono_mb_emit_ldarg (mb, argnum);
6038
6039 if (t->byref)
6040 mono_mb_emit_byte (mb, CEE_LDIND_I);
6041
6042 mono_mb_emit_stloc (mb, 1);
6043
6044 mono_mb_emit_ldloc (mb, 1);
6045 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
6046
6047 if (t->byref || (t->attrs & PARAM_ATTRIBUTE_OUT)) {
6048 mono_mb_emit_ldloc (mb, 1);
6049 mono_mb_emit_icon (mb, sizeof (MonoObject));
6050 mono_mb_emit_byte (mb, CEE_ADD);
6051 mono_mb_emit_stloc (mb, 1);
6052
6053 /* src = tmp_locals [i] */
6054 mono_mb_emit_ldloc (mb, conv_arg);
6055 mono_mb_emit_stloc (mb, 0);
6056
6057 /* emit valuetype conversion code */
6058 emit_struct_conv (mb, klass, TRUE);
6059
6060 /* Free the structure returned by the native code */
6061 emit_struct_free (mb, klass, conv_arg);
6062
6063 if (m->orig_conv_args [argnum]) {
6064 /*
6065 * If the native function changed the pointer, then free
6066 * the original structure plus the new pointer.
6067 */
6068 mono_mb_emit_ldloc (mb, m->orig_conv_args [argnum]);
6069 mono_mb_emit_ldloc (mb, conv_arg);
6070 pos2 = mono_mb_emit_branch (mb, CEE_BEQ);
6071
6072 if (!(t->attrs & PARAM_ATTRIBUTE_OUT)) {
6073 g_assert (m->orig_conv_args [argnum]);
6074
6075 emit_struct_free (mb, klass, m->orig_conv_args [argnum]);
6076 }
6077
6078 mono_mb_emit_ldloc (mb, conv_arg);
6079 mono_mb_emit_icall (mb, mono_marshal_free);
6080
6081 mono_mb_patch_branch (mb, pos2);
6082 }
6083 }
6084 else
6085 /* Free the original structure passed to native code */
6086 emit_struct_free (mb, klass, conv_arg);
6087
6088 mono_mb_patch_branch (mb, pos);
6089 break;
6090
6091 case MARSHAL_ACTION_PUSH:
6092 if (t->byref)
6093 mono_mb_emit_ldloc_addr (mb, conv_arg);
6094 else
6095 mono_mb_emit_ldloc (mb, conv_arg);
6096 break;
6097
6098 case MARSHAL_ACTION_CONV_RESULT:
6099 if (klass->delegate) {
6100 g_assert (!t->byref);
6101 mono_mb_emit_stloc (mb, 0);
6102 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6103 mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
6104 mono_mb_emit_ldloc (mb, 0);
6105 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL));
6106 mono_mb_emit_stloc (mb, 3);
6107 } else if (klass == mono_defaults.stringbuilder_class) {
6108 // FIXME:
6109 char *msg = g_strdup_printf ("Return marshalling of stringbuilders is not implemented.");
6110 mono_mb_emit_exception_marshal_directive (mb, msg);
6111 } else {
6112 /* set src */
6113 mono_mb_emit_stloc (mb, 0);
6114
6115 /* Make a copy since emit_conv modifies local 0 */
6116 loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6117 mono_mb_emit_ldloc (mb, 0);
6118 mono_mb_emit_stloc (mb, loc);
6119
6120 mono_mb_emit_byte (mb, CEE_LDNULL);
6121 mono_mb_emit_stloc (mb, 3);
6122
6123 mono_mb_emit_ldloc (mb, 0);
6124 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
6125
6126 /* allocate result object */
6127
6128 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6129 mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass);
6130 mono_mb_emit_stloc (mb, 3);
6131
6132 /* set dst */
6133
6134 mono_mb_emit_ldloc (mb, 3);
6135 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
6136 mono_mb_emit_stloc (mb, 1);
6137
6138 /* emit conversion code */
6139 emit_struct_conv (mb, klass, TRUE);
6140
6141 emit_struct_free (mb, klass, loc);
6142
6143 /* Free the pointer allocated by unmanaged code */
6144 mono_mb_emit_ldloc (mb, loc);
6145 mono_mb_emit_icall (mb, mono_marshal_free);
6146 mono_mb_patch_branch (mb, pos);
6147 }
6148 break;
6149
6150 case MARSHAL_ACTION_MANAGED_CONV_IN:
6151 conv_arg = mono_mb_add_local (mb, &klass->byval_arg);
6152
6153 if (klass->delegate) {
6154 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6155 mono_mb_emit_op (mb, CEE_MONO_CLASSCONST, klass);
6156 mono_mb_emit_ldarg (mb, argnum);
6157 if (t->byref)
6158 mono_mb_emit_byte (mb, CEE_LDIND_I);
6159 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_FTN_DEL, NULL));
6160 mono_mb_emit_stloc (mb, conv_arg);
6161 break;
6162 }
6163
6164 if (klass == mono_defaults.stringbuilder_class) {
6165 MonoMarshalNative encoding;
6166
6167 encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
6168
6169 // FIXME:
6170 g_assert (encoding == MONO_NATIVE_LPSTR || encoding == MONO_NATIVE_UTF8STR);
6171
6172 g_assert (!t->byref);
6173 g_assert (encoding != -1);
6174
6175 mono_mb_emit_ldarg (mb, argnum);
6176 mono_mb_emit_icall (mb, mono_string_utf8_to_builder2);
6177 mono_mb_emit_stloc (mb, conv_arg);
6178 break;
6179 }
6180
6181 /* The class can not have an automatic layout */
6182 if (mono_class_is_auto_layout (klass)) {
6183 mono_mb_emit_auto_layout_exception (mb, klass);
6184 break;
6185 }
6186
6187 if (t->attrs & PARAM_ATTRIBUTE_OUT) {
6188 mono_mb_emit_byte (mb, CEE_LDNULL);
6189 mono_mb_emit_stloc (mb, conv_arg);
6190 break;
6191 }
6192
6193 /* Set src */
6194 mono_mb_emit_ldarg (mb, argnum);
6195 if (t->byref) {
6196 int pos2;
6197
6198 /* Check for NULL and raise an exception */
6199 pos2 = mono_mb_emit_branch (mb, CEE_BRTRUE);
6200
6201 mono_mb_emit_exception (mb, "ArgumentNullException", NULL);
6202
6203 mono_mb_patch_branch (mb, pos2);
6204 mono_mb_emit_ldarg (mb, argnum);
6205 mono_mb_emit_byte (mb, CEE_LDIND_I);
6206 }
6207
6208 mono_mb_emit_stloc (mb, 0);
6209
6210 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
6211 mono_mb_emit_stloc (mb, conv_arg);
6212
6213 mono_mb_emit_ldloc (mb, 0);
6214 pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
6215
6216 /* Create and set dst */
6217 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
6218 mono_mb_emit_op (mb, CEE_MONO_NEWOBJ, klass);
6219 mono_mb_emit_stloc (mb, conv_arg);
6220 mono_mb_emit_ldloc (mb, conv_arg);
6221 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
6222 mono_mb_emit_stloc (mb, 1);
6223
6224 /* emit valuetype conversion code */
6225 emit_struct_conv (mb, klass, TRUE);
6226
6227 mono_mb_patch_branch (mb, pos);
6228 break;
6229
6230 case MARSHAL_ACTION_MANAGED_CONV_OUT:
6231 if (klass->delegate) {
6232 if (t->byref) {
6233 int stind_op;
6234 mono_mb_emit_ldarg (mb, argnum);
6235 mono_mb_emit_ldloc (mb, conv_arg);
6236 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, &stind_op));
6237 mono_mb_emit_byte (mb, stind_op);
6238 break;
6239 }
6240 }
6241
6242 if (t->byref) {
6243 /* Check for null */
6244 mono_mb_emit_ldloc (mb, conv_arg);
6245 pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
6246 mono_mb_emit_ldarg (mb, argnum);
6247 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
6248 mono_mb_emit_byte (mb, CEE_STIND_REF);
6249 pos2 = mono_mb_emit_branch (mb, CEE_BR);
6250
6251 mono_mb_patch_branch (mb, pos);
6252
6253 /* Set src */
6254 mono_mb_emit_ldloc (mb, conv_arg);
6255 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
6256 mono_mb_emit_stloc (mb, 0);
6257
6258 /* Allocate and set dest */
6259 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
6260 mono_mb_emit_byte (mb, CEE_CONV_I);
6261 mono_mb_emit_icall (mb, ves_icall_marshal_alloc);
6262 mono_mb_emit_stloc (mb, 1);
6263
6264 /* Update argument pointer */
6265 mono_mb_emit_ldarg (mb, argnum);
6266 mono_mb_emit_ldloc (mb, 1);
6267 mono_mb_emit_byte (mb, CEE_STIND_I);
6268
6269 /* emit valuetype conversion code */
6270 emit_struct_conv (mb, klass, FALSE);
6271
6272 mono_mb_patch_branch (mb, pos2);
6273 } else if (klass == mono_defaults.stringbuilder_class) {
6274 // FIXME: What to do here ?
6275 } else {
6276 /* byval [Out] marshalling */
6277
6278 /* FIXME: Handle null */
6279
6280 /* Set src */
6281 mono_mb_emit_ldloc (mb, conv_arg);
6282 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
6283 mono_mb_emit_stloc (mb, 0);
6284
6285 /* Set dest */
6286 mono_mb_emit_ldarg (mb, argnum);
6287 mono_mb_emit_stloc (mb, 1);
6288
6289 /* emit valuetype conversion code */
6290 emit_struct_conv (mb, klass, FALSE);
6291 }
6292 break;
6293
6294 case MARSHAL_ACTION_MANAGED_CONV_RESULT:
6295 if (klass->delegate) {
6296 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_DEL_FTN, NULL));
6297 mono_mb_emit_stloc (mb, 3);
6298 break;
6299 }
6300
6301 /* The class can not have an automatic layout */
6302 if (mono_class_is_auto_layout (klass)) {
6303 mono_mb_emit_auto_layout_exception (mb, klass);
6304 break;
6305 }
6306
6307 mono_mb_emit_stloc (mb, 0);
6308 /* Check for null */
6309 mono_mb_emit_ldloc (mb, 0);
6310 pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
6311 mono_mb_emit_byte (mb, CEE_LDNULL);
6312 mono_mb_emit_stloc (mb, 3);
6313 pos2 = mono_mb_emit_branch (mb, CEE_BR);
6314
6315 mono_mb_patch_branch (mb, pos);
6316
6317 /* Set src */
6318 mono_mb_emit_ldloc (mb, 0);
6319 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
6320 mono_mb_emit_stloc (mb, 0);
6321
6322 /* Allocate and set dest */
6323 mono_mb_emit_icon (mb, mono_class_native_size (klass, NULL));
6324 mono_mb_emit_byte (mb, CEE_CONV_I);
6325 mono_mb_emit_icall (mb, ves_icall_marshal_alloc);
6326 mono_mb_emit_byte (mb, CEE_DUP);
6327 mono_mb_emit_stloc (mb, 1);
6328 mono_mb_emit_stloc (mb, 3);
6329
6330 emit_struct_conv (mb, klass, FALSE);
6331
6332 mono_mb_patch_branch (mb, pos2);
6333 break;
6334
6335 default:
6336 g_assert_not_reached ();
6337 }
6338 #endif
6339 return conv_arg;
6340 }
6341
6342 #ifdef ENABLE_ILGEN
6343 #ifndef DISABLE_COM
6344
6345 static int
emit_marshal_variant(EmitMarshalContext * m,int argnum,MonoType * t,MonoMarshalSpec * spec,int conv_arg,MonoType ** conv_arg_type,MarshalAction action)6346 emit_marshal_variant (EmitMarshalContext *m, int argnum, MonoType *t,
6347 MonoMarshalSpec *spec,
6348 int conv_arg, MonoType **conv_arg_type,
6349 MarshalAction action)
6350 {
6351 MonoMethodBuilder *mb = m->mb;
6352 static MonoMethod *get_object_for_native_variant = NULL;
6353 static MonoMethod *get_native_variant_for_object = NULL;
6354
6355 if (!get_object_for_native_variant)
6356 get_object_for_native_variant = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetObjectForNativeVariant", 1);
6357 g_assert (get_object_for_native_variant);
6358
6359 if (!get_native_variant_for_object)
6360 get_native_variant_for_object = mono_class_get_method_from_name (mono_defaults.marshal_class, "GetNativeVariantForObject", 2);
6361 g_assert (get_native_variant_for_object);
6362
6363 switch (action) {
6364 case MARSHAL_ACTION_CONV_IN: {
6365 conv_arg = mono_mb_add_local (mb, &mono_class_get_variant_class ()->byval_arg);
6366
6367 if (t->byref)
6368 *conv_arg_type = &mono_class_get_variant_class ()->this_arg;
6369 else
6370 *conv_arg_type = &mono_class_get_variant_class ()->byval_arg;
6371
6372 if (t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN) && t->attrs & PARAM_ATTRIBUTE_OUT)
6373 break;
6374
6375 mono_mb_emit_ldarg (mb, argnum);
6376 if (t->byref)
6377 mono_mb_emit_byte(mb, CEE_LDIND_REF);
6378 mono_mb_emit_ldloc_addr (mb, conv_arg);
6379 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
6380 break;
6381 }
6382
6383 case MARSHAL_ACTION_CONV_OUT: {
6384 static MonoMethod *variant_clear = NULL;
6385
6386 if (!variant_clear)
6387 variant_clear = mono_class_get_method_from_name (mono_class_get_variant_class (), "Clear", 0);
6388 g_assert (variant_clear);
6389
6390
6391 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) {
6392 mono_mb_emit_ldarg (mb, argnum);
6393 mono_mb_emit_ldloc_addr (mb, conv_arg);
6394 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
6395 mono_mb_emit_byte (mb, CEE_STIND_REF);
6396 }
6397
6398 mono_mb_emit_ldloc_addr (mb, conv_arg);
6399 mono_mb_emit_managed_call (mb, variant_clear, NULL);
6400 break;
6401 }
6402
6403 case MARSHAL_ACTION_PUSH:
6404 if (t->byref)
6405 mono_mb_emit_ldloc_addr (mb, conv_arg);
6406 else
6407 mono_mb_emit_ldloc (mb, conv_arg);
6408 break;
6409
6410 case MARSHAL_ACTION_CONV_RESULT: {
6411 char *msg = g_strdup ("Marshalling of VARIANT not supported as a return type.");
6412 mono_mb_emit_exception_marshal_directive (mb, msg);
6413 break;
6414 }
6415
6416 case MARSHAL_ACTION_MANAGED_CONV_IN: {
6417 conv_arg = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
6418
6419 if (t->byref)
6420 *conv_arg_type = &mono_class_get_variant_class ()->this_arg;
6421 else
6422 *conv_arg_type = &mono_class_get_variant_class ()->byval_arg;
6423
6424 if (t->byref && !(t->attrs & PARAM_ATTRIBUTE_IN) && t->attrs & PARAM_ATTRIBUTE_OUT)
6425 break;
6426
6427 if (t->byref)
6428 mono_mb_emit_ldarg (mb, argnum);
6429 else
6430 mono_mb_emit_ldarg_addr (mb, argnum);
6431 mono_mb_emit_managed_call (mb, get_object_for_native_variant, NULL);
6432 mono_mb_emit_stloc (mb, conv_arg);
6433 break;
6434 }
6435
6436 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
6437 if (t->byref && (t->attrs & PARAM_ATTRIBUTE_OUT || !(t->attrs & PARAM_ATTRIBUTE_IN))) {
6438 mono_mb_emit_ldloc (mb, conv_arg);
6439 mono_mb_emit_ldarg (mb, argnum);
6440 mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL);
6441 }
6442 break;
6443 }
6444
6445 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
6446 char *msg = g_strdup ("Marshalling of VARIANT not supported as a return type.");
6447 mono_mb_emit_exception_marshal_directive (mb, msg);
6448 break;
6449 }
6450
6451 default:
6452 g_assert_not_reached ();
6453 }
6454
6455 return conv_arg;
6456 }
6457
6458 #endif /* DISABLE_COM */
6459 #endif /* ENABLE_ILGEN */
6460
6461 static gboolean
mono_pinvoke_is_unicode(MonoMethodPInvoke * piinfo)6462 mono_pinvoke_is_unicode (MonoMethodPInvoke *piinfo)
6463 {
6464 switch (piinfo->piflags & PINVOKE_ATTRIBUTE_CHAR_SET_MASK) {
6465 case PINVOKE_ATTRIBUTE_CHAR_SET_ANSI:
6466 return FALSE;
6467 case PINVOKE_ATTRIBUTE_CHAR_SET_UNICODE:
6468 return TRUE;
6469 case PINVOKE_ATTRIBUTE_CHAR_SET_AUTO:
6470 default:
6471 #ifdef TARGET_WIN32
6472 return TRUE;
6473 #else
6474 return FALSE;
6475 #endif
6476 }
6477 }
6478
6479
6480 static int
emit_marshal_array(EmitMarshalContext * m,int argnum,MonoType * t,MonoMarshalSpec * spec,int conv_arg,MonoType ** conv_arg_type,MarshalAction action)6481 emit_marshal_array (EmitMarshalContext *m, int argnum, MonoType *t,
6482 MonoMarshalSpec *spec,
6483 int conv_arg, MonoType **conv_arg_type,
6484 MarshalAction action)
6485 {
6486 #ifndef ENABLE_ILGEN
6487 switch (action) {
6488 case MARSHAL_ACTION_CONV_IN:
6489 *conv_arg_type = &mono_defaults.object_class->byval_arg;
6490 break;
6491 case MARSHAL_ACTION_MANAGED_CONV_IN:
6492 *conv_arg_type = &mono_defaults.int_class->byval_arg;
6493 break;
6494 }
6495 #else
6496 MonoMethodBuilder *mb = m->mb;
6497 MonoClass *klass = mono_class_from_mono_type (t);
6498 gboolean need_convert, need_free;
6499 MonoMarshalNative encoding;
6500
6501 encoding = mono_marshal_get_string_encoding (m->piinfo, spec);
6502
6503 switch (action) {
6504 case MARSHAL_ACTION_CONV_IN:
6505 *conv_arg_type = &mono_defaults.object_class->byval_arg;
6506 conv_arg = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
6507
6508 if (klass->element_class->blittable) {
6509 mono_mb_emit_ldarg (mb, argnum);
6510 if (t->byref)
6511 mono_mb_emit_byte (mb, CEE_LDIND_I);
6512 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_CONV_ARRAY_LPARRAY, NULL));
6513 mono_mb_emit_stloc (mb, conv_arg);
6514 } else {
6515 MonoClass *eklass;
6516 guint32 label1, label2, label3;
6517 int index_var, src_var, dest_ptr, esize;
6518 MonoMarshalConv conv;
6519 gboolean is_string = FALSE;
6520
6521 dest_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6522
6523 eklass = klass->element_class;
6524
6525 if (eklass == mono_defaults.string_class) {
6526 is_string = TRUE;
6527 conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec);
6528 }
6529 else if (eklass == mono_defaults.stringbuilder_class) {
6530 is_string = TRUE;
6531 conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
6532 }
6533 else
6534 conv = MONO_MARSHAL_CONV_INVALID;
6535
6536 if (is_string && conv == MONO_MARSHAL_CONV_INVALID) {
6537 char *msg = g_strdup_printf ("string/stringbuilder marshalling conversion %d not implemented", encoding);
6538 mono_mb_emit_exception_marshal_directive (mb, msg);
6539 break;
6540 }
6541
6542 src_var = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
6543 mono_mb_emit_ldarg (mb, argnum);
6544 if (t->byref)
6545 mono_mb_emit_byte (mb, CEE_LDIND_I);
6546 mono_mb_emit_stloc (mb, src_var);
6547
6548 /* Check null */
6549 mono_mb_emit_ldloc (mb, src_var);
6550 mono_mb_emit_stloc (mb, conv_arg);
6551 mono_mb_emit_ldloc (mb, src_var);
6552 label1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
6553
6554 if (is_string)
6555 esize = sizeof (gpointer);
6556 else if (eklass == mono_defaults.char_class) /*can't call mono_marshal_type_size since it causes all sorts of asserts*/
6557 esize = mono_pinvoke_is_unicode (m->piinfo) ? 2 : 1;
6558 else
6559 esize = mono_class_native_size (eklass, NULL);
6560
6561 /* allocate space for the native struct and store the address */
6562 mono_mb_emit_icon (mb, esize);
6563 mono_mb_emit_ldloc (mb, src_var);
6564 mono_mb_emit_byte (mb, CEE_LDLEN);
6565
6566 if (eklass == mono_defaults.string_class) {
6567 /* Make the array bigger for the terminating null */
6568 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
6569 mono_mb_emit_byte (mb, CEE_ADD);
6570 }
6571 mono_mb_emit_byte (mb, CEE_MUL);
6572 mono_mb_emit_byte (mb, CEE_PREFIX1);
6573 mono_mb_emit_byte (mb, CEE_LOCALLOC);
6574 mono_mb_emit_stloc (mb, conv_arg);
6575
6576 mono_mb_emit_ldloc (mb, conv_arg);
6577 mono_mb_emit_stloc (mb, dest_ptr);
6578
6579 /* Emit marshalling loop */
6580 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6581 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
6582 mono_mb_emit_stloc (mb, index_var);
6583 label2 = mono_mb_get_label (mb);
6584 mono_mb_emit_ldloc (mb, index_var);
6585 mono_mb_emit_ldloc (mb, src_var);
6586 mono_mb_emit_byte (mb, CEE_LDLEN);
6587 label3 = mono_mb_emit_branch (mb, CEE_BGE);
6588
6589 /* Emit marshalling code */
6590
6591 if (is_string) {
6592 int stind_op;
6593 mono_mb_emit_ldloc (mb, dest_ptr);
6594 mono_mb_emit_ldloc (mb, src_var);
6595 mono_mb_emit_ldloc (mb, index_var);
6596 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
6597 mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
6598 mono_mb_emit_byte (mb, stind_op);
6599 } else {
6600 /* set the src_ptr */
6601 mono_mb_emit_ldloc (mb, src_var);
6602 mono_mb_emit_ldloc (mb, index_var);
6603 mono_mb_emit_op (mb, CEE_LDELEMA, eklass);
6604 mono_mb_emit_stloc (mb, 0);
6605
6606 /* set dst_ptr */
6607 mono_mb_emit_ldloc (mb, dest_ptr);
6608 mono_mb_emit_stloc (mb, 1);
6609
6610 /* emit valuetype conversion code */
6611 emit_struct_conv_full (mb, eklass, FALSE, 0, eklass == mono_defaults.char_class ? encoding : (MonoMarshalNative)-1);
6612 }
6613
6614 mono_mb_emit_add_to_local (mb, index_var, 1);
6615 mono_mb_emit_add_to_local (mb, dest_ptr, esize);
6616
6617 mono_mb_emit_branch_label (mb, CEE_BR, label2);
6618
6619 mono_mb_patch_branch (mb, label3);
6620
6621 if (eklass == mono_defaults.string_class) {
6622 /* Null terminate */
6623 mono_mb_emit_ldloc (mb, dest_ptr);
6624 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
6625 mono_mb_emit_byte (mb, CEE_STIND_REF);
6626 }
6627
6628 mono_mb_patch_branch (mb, label1);
6629 }
6630
6631 break;
6632
6633 case MARSHAL_ACTION_CONV_OUT:
6634 /* Unicode character arrays are implicitly marshalled as [Out] under MS.NET */
6635 need_convert = ((klass->element_class == mono_defaults.char_class) && (encoding == MONO_NATIVE_LPWSTR)) || (klass->element_class == mono_defaults.stringbuilder_class) || (t->attrs & PARAM_ATTRIBUTE_OUT);
6636 need_free = mono_marshal_need_free (&klass->element_class->byval_arg,
6637 m->piinfo, spec);
6638
6639 if ((t->attrs & PARAM_ATTRIBUTE_OUT) && spec && spec->native == MONO_NATIVE_LPARRAY && spec->data.array_data.param_num != -1) {
6640 int param_num = spec->data.array_data.param_num;
6641 MonoType *param_type;
6642
6643 param_type = m->sig->params [param_num];
6644
6645 if (param_type->byref && param_type->type != MONO_TYPE_I4) {
6646 char *msg = g_strdup ("Not implemented.");
6647 mono_mb_emit_exception_marshal_directive (mb, msg);
6648 break;
6649 }
6650
6651 if (t->byref ) {
6652 mono_mb_emit_ldarg (mb, argnum);
6653
6654 /* Create the managed array */
6655 mono_mb_emit_ldarg (mb, param_num);
6656 if (m->sig->params [param_num]->byref)
6657 // FIXME: Support other types
6658 mono_mb_emit_byte (mb, CEE_LDIND_I4);
6659 mono_mb_emit_byte (mb, CEE_CONV_OVF_I);
6660 mono_mb_emit_op (mb, CEE_NEWARR, klass->element_class);
6661 /* Store into argument */
6662 mono_mb_emit_byte (mb, CEE_STIND_REF);
6663 }
6664 }
6665
6666 if (need_convert || need_free) {
6667 /* FIXME: Optimize blittable case */
6668 MonoClass *eklass;
6669 guint32 label1, label2, label3;
6670 int index_var, src_ptr, loc, esize;
6671
6672 eklass = klass->element_class;
6673 if ((eklass == mono_defaults.stringbuilder_class) || (eklass == mono_defaults.string_class))
6674 esize = sizeof (gpointer);
6675 else if (eklass == mono_defaults.char_class)
6676 esize = mono_pinvoke_is_unicode (m->piinfo) ? 2 : 1;
6677 else
6678 esize = mono_class_native_size (eklass, NULL);
6679 src_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6680 loc = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6681
6682 /* Check null */
6683 mono_mb_emit_ldarg (mb, argnum);
6684 if (t->byref)
6685 mono_mb_emit_byte (mb, CEE_LDIND_I);
6686 label1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
6687
6688 mono_mb_emit_ldloc (mb, conv_arg);
6689 mono_mb_emit_stloc (mb, src_ptr);
6690
6691 /* Emit marshalling loop */
6692 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6693 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
6694 mono_mb_emit_stloc (mb, index_var);
6695 label2 = mono_mb_get_label (mb);
6696 mono_mb_emit_ldloc (mb, index_var);
6697 mono_mb_emit_ldarg (mb, argnum);
6698 if (t->byref)
6699 mono_mb_emit_byte (mb, CEE_LDIND_REF);
6700 mono_mb_emit_byte (mb, CEE_LDLEN);
6701 label3 = mono_mb_emit_branch (mb, CEE_BGE);
6702
6703 /* Emit marshalling code */
6704
6705 if (eklass == mono_defaults.stringbuilder_class) {
6706 gboolean need_free2;
6707 MonoMarshalConv conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free2);
6708
6709 g_assert (conv != MONO_MARSHAL_CONV_INVALID);
6710
6711 /* dest */
6712 mono_mb_emit_ldarg (mb, argnum);
6713 if (t->byref)
6714 mono_mb_emit_byte (mb, CEE_LDIND_I);
6715 mono_mb_emit_ldloc (mb, index_var);
6716 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
6717
6718 /* src */
6719 mono_mb_emit_ldloc (mb, src_ptr);
6720 mono_mb_emit_byte (mb, CEE_LDIND_I);
6721
6722 mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
6723
6724 if (need_free) {
6725 /* src */
6726 mono_mb_emit_ldloc (mb, src_ptr);
6727 mono_mb_emit_byte (mb, CEE_LDIND_I);
6728
6729 mono_mb_emit_icall (mb, mono_marshal_free);
6730 }
6731 }
6732 else if (eklass == mono_defaults.string_class) {
6733 if (need_free) {
6734 /* src */
6735 mono_mb_emit_ldloc (mb, src_ptr);
6736 mono_mb_emit_byte (mb, CEE_LDIND_I);
6737
6738 mono_mb_emit_icall (mb, mono_marshal_free);
6739 }
6740 }
6741 else {
6742 if (need_convert) {
6743 /* set the src_ptr */
6744 mono_mb_emit_ldloc (mb, src_ptr);
6745 mono_mb_emit_stloc (mb, 0);
6746
6747 /* set dst_ptr */
6748 mono_mb_emit_ldarg (mb, argnum);
6749 if (t->byref)
6750 mono_mb_emit_byte (mb, CEE_LDIND_REF);
6751 mono_mb_emit_ldloc (mb, index_var);
6752 mono_mb_emit_op (mb, CEE_LDELEMA, eklass);
6753 mono_mb_emit_stloc (mb, 1);
6754
6755 /* emit valuetype conversion code */
6756 emit_struct_conv_full (mb, eklass, TRUE, 0, eklass == mono_defaults.char_class ? encoding : (MonoMarshalNative)-1);
6757 }
6758
6759 if (need_free) {
6760 mono_mb_emit_ldloc (mb, src_ptr);
6761 mono_mb_emit_stloc (mb, loc);
6762 mono_mb_emit_ldloc (mb, loc);
6763
6764 emit_struct_free (mb, eklass, loc);
6765 }
6766 }
6767
6768 mono_mb_emit_add_to_local (mb, index_var, 1);
6769 mono_mb_emit_add_to_local (mb, src_ptr, esize);
6770
6771 mono_mb_emit_branch_label (mb, CEE_BR, label2);
6772
6773 mono_mb_patch_branch (mb, label1);
6774 mono_mb_patch_branch (mb, label3);
6775 }
6776
6777 if (klass->element_class->blittable) {
6778 /* free memory allocated (if any) by MONO_MARSHAL_CONV_ARRAY_LPARRAY */
6779
6780 mono_mb_emit_ldarg (mb, argnum);
6781 if (t->byref)
6782 mono_mb_emit_byte (mb, CEE_LDIND_REF);
6783 mono_mb_emit_ldloc (mb, conv_arg);
6784 mono_mb_emit_icall (mb, conv_to_icall (MONO_MARSHAL_FREE_LPARRAY, NULL));
6785 }
6786
6787 break;
6788
6789 case MARSHAL_ACTION_PUSH:
6790 if (t->byref)
6791 mono_mb_emit_ldloc_addr (mb, conv_arg);
6792 else
6793 mono_mb_emit_ldloc (mb, conv_arg);
6794 break;
6795
6796 case MARSHAL_ACTION_CONV_RESULT:
6797 /* fixme: we need conversions here */
6798 mono_mb_emit_stloc (mb, 3);
6799 break;
6800
6801 case MARSHAL_ACTION_MANAGED_CONV_IN: {
6802 MonoClass *eklass;
6803 guint32 label1, label2, label3;
6804 int index_var, src_ptr, esize, param_num, num_elem;
6805 MonoMarshalConv conv;
6806 gboolean is_string = FALSE;
6807
6808 conv_arg = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
6809 *conv_arg_type = &mono_defaults.int_class->byval_arg;
6810
6811 if (t->byref) {
6812 char *msg = g_strdup ("Byref array marshalling to managed code is not implemented.");
6813 mono_mb_emit_exception_marshal_directive (mb, msg);
6814 return conv_arg;
6815 }
6816 if (!spec) {
6817 char *msg = g_strdup ("[MarshalAs] attribute required to marshal arrays to managed code.");
6818 mono_mb_emit_exception_marshal_directive (mb, msg);
6819 return conv_arg;
6820 }
6821 if (spec->native != MONO_NATIVE_LPARRAY) {
6822 char *msg = g_strdup ("Non LPArray marshalling of arrays to managed code is not implemented.");
6823 mono_mb_emit_exception_marshal_directive (mb, msg);
6824 return conv_arg;
6825 }
6826
6827 /* FIXME: t is from the method which is wrapped, not the delegate type */
6828 /* g_assert (t->attrs & PARAM_ATTRIBUTE_IN); */
6829
6830 param_num = spec->data.array_data.param_num;
6831 num_elem = spec->data.array_data.num_elem;
6832 if (spec->data.array_data.elem_mult == 0)
6833 /* param_num is not specified */
6834 param_num = -1;
6835
6836 if (param_num == -1) {
6837 if (num_elem <= 0) {
6838 char *msg = g_strdup ("Either SizeConst or SizeParamIndex should be specified when marshalling arrays to managed code.");
6839 mono_mb_emit_exception_marshal_directive (mb, msg);
6840 return conv_arg;
6841 }
6842 }
6843
6844 /* FIXME: Optimize blittable case */
6845
6846 eklass = klass->element_class;
6847 if (eklass == mono_defaults.string_class) {
6848 is_string = TRUE;
6849 conv = mono_marshal_get_ptr_to_string_conv (m->piinfo, spec, &need_free);
6850 }
6851 else if (eklass == mono_defaults.stringbuilder_class) {
6852 is_string = TRUE;
6853 conv = mono_marshal_get_ptr_to_stringbuilder_conv (m->piinfo, spec, &need_free);
6854 }
6855 else
6856 conv = MONO_MARSHAL_CONV_INVALID;
6857
6858 mono_marshal_load_type_info (eklass);
6859
6860 if (is_string)
6861 esize = sizeof (gpointer);
6862 else
6863 esize = mono_class_native_size (eklass, NULL);
6864 src_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6865
6866 mono_mb_emit_byte (mb, CEE_LDNULL);
6867 mono_mb_emit_stloc (mb, conv_arg);
6868
6869 /* Check param index */
6870 if (param_num != -1) {
6871 if (param_num >= m->sig->param_count) {
6872 char *msg = g_strdup ("Array size control parameter index is out of range.");
6873 mono_mb_emit_exception_marshal_directive (mb, msg);
6874 return conv_arg;
6875 }
6876 switch (m->sig->params [param_num]->type) {
6877 case MONO_TYPE_I1:
6878 case MONO_TYPE_U1:
6879 case MONO_TYPE_I2:
6880 case MONO_TYPE_U2:
6881 case MONO_TYPE_I4:
6882 case MONO_TYPE_U4:
6883 case MONO_TYPE_I:
6884 case MONO_TYPE_U:
6885 case MONO_TYPE_I8:
6886 case MONO_TYPE_U8:
6887 break;
6888 default: {
6889 char *msg = g_strdup ("Array size control parameter must be an integral type.");
6890 mono_mb_emit_exception_marshal_directive (mb, msg);
6891 return conv_arg;
6892 }
6893 }
6894 }
6895
6896 /* Check null */
6897 mono_mb_emit_ldarg (mb, argnum);
6898 label1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
6899
6900 mono_mb_emit_ldarg (mb, argnum);
6901 mono_mb_emit_stloc (mb, src_ptr);
6902
6903 /* Create managed array */
6904 /*
6905 * The LPArray marshalling spec says that sometimes param_num starts
6906 * from 1, sometimes it starts from 0. But MS seems to allways start
6907 * from 0.
6908 */
6909
6910 if (param_num == -1) {
6911 mono_mb_emit_icon (mb, num_elem);
6912 } else {
6913 mono_mb_emit_ldarg (mb, param_num);
6914 if (num_elem > 0) {
6915 mono_mb_emit_icon (mb, num_elem);
6916 mono_mb_emit_byte (mb, CEE_ADD);
6917 }
6918 mono_mb_emit_byte (mb, CEE_CONV_OVF_I);
6919 }
6920
6921 mono_mb_emit_op (mb, CEE_NEWARR, eklass);
6922 mono_mb_emit_stloc (mb, conv_arg);
6923
6924 if (eklass->blittable) {
6925 mono_mb_emit_ldloc (mb, conv_arg);
6926 mono_mb_emit_byte (mb, CEE_CONV_I);
6927 mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoArray, vector));
6928 mono_mb_emit_byte (mb, CEE_ADD);
6929 mono_mb_emit_ldarg (mb, argnum);
6930 mono_mb_emit_ldloc (mb, conv_arg);
6931 mono_mb_emit_byte (mb, CEE_LDLEN);
6932 mono_mb_emit_icon (mb, esize);
6933 mono_mb_emit_byte (mb, CEE_MUL);
6934 mono_mb_emit_byte (mb, CEE_PREFIX1);
6935 mono_mb_emit_byte (mb, CEE_CPBLK);
6936 mono_mb_patch_branch (mb, label1);
6937 break;
6938 }
6939
6940 /* Emit marshalling loop */
6941 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
6942 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
6943 mono_mb_emit_stloc (mb, index_var);
6944 label2 = mono_mb_get_label (mb);
6945 mono_mb_emit_ldloc (mb, index_var);
6946 mono_mb_emit_ldloc (mb, conv_arg);
6947 mono_mb_emit_byte (mb, CEE_LDLEN);
6948 label3 = mono_mb_emit_branch (mb, CEE_BGE);
6949
6950 /* Emit marshalling code */
6951 if (is_string) {
6952 g_assert (conv != MONO_MARSHAL_CONV_INVALID);
6953
6954 mono_mb_emit_ldloc (mb, conv_arg);
6955 mono_mb_emit_ldloc (mb, index_var);
6956
6957 mono_mb_emit_ldloc (mb, src_ptr);
6958 mono_mb_emit_byte (mb, CEE_LDIND_I);
6959
6960 mono_mb_emit_icall (mb, conv_to_icall (conv, NULL));
6961 mono_mb_emit_byte (mb, CEE_STELEM_REF);
6962 }
6963 else {
6964 char *msg = g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented.");
6965 mono_mb_emit_exception_marshal_directive (mb, msg);
6966 return conv_arg;
6967 }
6968
6969 mono_mb_emit_add_to_local (mb, index_var, 1);
6970 mono_mb_emit_add_to_local (mb, src_ptr, esize);
6971
6972 mono_mb_emit_branch_label (mb, CEE_BR, label2);
6973
6974 mono_mb_patch_branch (mb, label1);
6975 mono_mb_patch_branch (mb, label3);
6976
6977 break;
6978 }
6979 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
6980 MonoClass *eklass;
6981 guint32 label1, label2, label3;
6982 int index_var, dest_ptr, esize, param_num, num_elem;
6983 MonoMarshalConv conv;
6984 gboolean is_string = FALSE;
6985
6986 if (!spec)
6987 /* Already handled in CONV_IN */
6988 break;
6989
6990 /* These are already checked in CONV_IN */
6991 g_assert (!t->byref);
6992 g_assert (spec->native == MONO_NATIVE_LPARRAY);
6993 g_assert (t->attrs & PARAM_ATTRIBUTE_OUT);
6994
6995 param_num = spec->data.array_data.param_num;
6996 num_elem = spec->data.array_data.num_elem;
6997
6998 if (spec->data.array_data.elem_mult == 0)
6999 /* param_num is not specified */
7000 param_num = -1;
7001
7002 if (param_num == -1) {
7003 if (num_elem <= 0) {
7004 g_assert_not_reached ();
7005 }
7006 }
7007
7008 /* FIXME: Optimize blittable case */
7009
7010 eklass = klass->element_class;
7011 if (eklass == mono_defaults.string_class) {
7012 is_string = TRUE;
7013 conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec);
7014 }
7015 else if (eklass == mono_defaults.stringbuilder_class) {
7016 is_string = TRUE;
7017 conv = mono_marshal_get_stringbuilder_to_ptr_conv (m->piinfo, spec);
7018 }
7019 else
7020 conv = MONO_MARSHAL_CONV_INVALID;
7021
7022 mono_marshal_load_type_info (eklass);
7023
7024 if (is_string)
7025 esize = sizeof (gpointer);
7026 else
7027 esize = mono_class_native_size (eklass, NULL);
7028
7029 dest_ptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7030
7031 /* Check null */
7032 mono_mb_emit_ldloc (mb, conv_arg);
7033 label1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
7034
7035 mono_mb_emit_ldarg (mb, argnum);
7036 mono_mb_emit_stloc (mb, dest_ptr);
7037
7038 if (eklass->blittable) {
7039 /* dest */
7040 mono_mb_emit_ldarg (mb, argnum);
7041 /* src */
7042 mono_mb_emit_ldloc (mb, conv_arg);
7043 mono_mb_emit_byte (mb, CEE_CONV_I);
7044 mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoArray, vector));
7045 mono_mb_emit_byte (mb, CEE_ADD);
7046 /* length */
7047 mono_mb_emit_ldloc (mb, conv_arg);
7048 mono_mb_emit_byte (mb, CEE_LDLEN);
7049 mono_mb_emit_icon (mb, esize);
7050 mono_mb_emit_byte (mb, CEE_MUL);
7051 mono_mb_emit_byte (mb, CEE_PREFIX1);
7052 mono_mb_emit_byte (mb, CEE_CPBLK);
7053 break;
7054 }
7055
7056 /* Emit marshalling loop */
7057 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7058 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
7059 mono_mb_emit_stloc (mb, index_var);
7060 label2 = mono_mb_get_label (mb);
7061 mono_mb_emit_ldloc (mb, index_var);
7062 mono_mb_emit_ldloc (mb, conv_arg);
7063 mono_mb_emit_byte (mb, CEE_LDLEN);
7064 label3 = mono_mb_emit_branch (mb, CEE_BGE);
7065
7066 /* Emit marshalling code */
7067 if (is_string) {
7068 int stind_op;
7069 g_assert (conv != MONO_MARSHAL_CONV_INVALID);
7070
7071 /* dest */
7072 mono_mb_emit_ldloc (mb, dest_ptr);
7073
7074 /* src */
7075 mono_mb_emit_ldloc (mb, conv_arg);
7076 mono_mb_emit_ldloc (mb, index_var);
7077
7078 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
7079
7080 mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
7081 mono_mb_emit_byte (mb, stind_op);
7082 }
7083 else {
7084 char *msg = g_strdup ("Marshalling of non-string and non-blittable arrays to managed code is not implemented.");
7085 mono_mb_emit_exception_marshal_directive (mb, msg);
7086 return conv_arg;
7087 }
7088
7089 mono_mb_emit_add_to_local (mb, index_var, 1);
7090 mono_mb_emit_add_to_local (mb, dest_ptr, esize);
7091
7092 mono_mb_emit_branch_label (mb, CEE_BR, label2);
7093
7094 mono_mb_patch_branch (mb, label1);
7095 mono_mb_patch_branch (mb, label3);
7096
7097 break;
7098 }
7099 case MARSHAL_ACTION_MANAGED_CONV_RESULT: {
7100 MonoClass *eklass;
7101 guint32 label1, label2, label3;
7102 int index_var, src, dest, esize;
7103 MonoMarshalConv conv = MONO_MARSHAL_CONV_INVALID;
7104 gboolean is_string = FALSE;
7105
7106 g_assert (!t->byref);
7107
7108 eklass = klass->element_class;
7109
7110 mono_marshal_load_type_info (eklass);
7111
7112 if (eklass == mono_defaults.string_class) {
7113 is_string = TRUE;
7114 conv = mono_marshal_get_string_to_ptr_conv (m->piinfo, spec);
7115 }
7116 else {
7117 g_assert_not_reached ();
7118 }
7119
7120 if (is_string)
7121 esize = sizeof (gpointer);
7122 else if (eklass == mono_defaults.char_class)
7123 esize = mono_pinvoke_is_unicode (m->piinfo) ? 2 : 1;
7124 else
7125 esize = mono_class_native_size (eklass, NULL);
7126
7127 src = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
7128 dest = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7129
7130 mono_mb_emit_stloc (mb, src);
7131 mono_mb_emit_ldloc (mb, src);
7132 mono_mb_emit_stloc (mb, 3);
7133
7134 /* Check for null */
7135 mono_mb_emit_ldloc (mb, src);
7136 label1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
7137
7138 /* Allocate native array */
7139 mono_mb_emit_icon (mb, esize);
7140 mono_mb_emit_ldloc (mb, src);
7141 mono_mb_emit_byte (mb, CEE_LDLEN);
7142
7143 if (eklass == mono_defaults.string_class) {
7144 /* Make the array bigger for the terminating null */
7145 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
7146 mono_mb_emit_byte (mb, CEE_ADD);
7147 }
7148 mono_mb_emit_byte (mb, CEE_MUL);
7149 mono_mb_emit_icall (mb, ves_icall_marshal_alloc);
7150 mono_mb_emit_stloc (mb, dest);
7151 mono_mb_emit_ldloc (mb, dest);
7152 mono_mb_emit_stloc (mb, 3);
7153
7154 /* Emit marshalling loop */
7155 index_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7156 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
7157 mono_mb_emit_stloc (mb, index_var);
7158 label2 = mono_mb_get_label (mb);
7159 mono_mb_emit_ldloc (mb, index_var);
7160 mono_mb_emit_ldloc (mb, src);
7161 mono_mb_emit_byte (mb, CEE_LDLEN);
7162 label3 = mono_mb_emit_branch (mb, CEE_BGE);
7163
7164 /* Emit marshalling code */
7165 if (is_string) {
7166 int stind_op;
7167 g_assert (conv != MONO_MARSHAL_CONV_INVALID);
7168
7169 /* dest */
7170 mono_mb_emit_ldloc (mb, dest);
7171
7172 /* src */
7173 mono_mb_emit_ldloc (mb, src);
7174 mono_mb_emit_ldloc (mb, index_var);
7175
7176 mono_mb_emit_byte (mb, CEE_LDELEM_REF);
7177
7178 mono_mb_emit_icall (mb, conv_to_icall (conv, &stind_op));
7179 mono_mb_emit_byte (mb, stind_op);
7180 }
7181 else {
7182 char *msg = g_strdup ("Marshalling of non-string arrays to managed code is not implemented.");
7183 mono_mb_emit_exception_marshal_directive (mb, msg);
7184 return conv_arg;
7185 }
7186
7187 mono_mb_emit_add_to_local (mb, index_var, 1);
7188 mono_mb_emit_add_to_local (mb, dest, esize);
7189
7190 mono_mb_emit_branch_label (mb, CEE_BR, label2);
7191
7192 mono_mb_patch_branch (mb, label3);
7193 mono_mb_patch_branch (mb, label1);
7194 break;
7195 }
7196 default:
7197 g_assert_not_reached ();
7198 }
7199 #endif
7200 return conv_arg;
7201 }
7202
7203 static MonoType*
marshal_boolean_conv_in_get_local_type(MonoMarshalSpec * spec,guint8 * ldc_op)7204 marshal_boolean_conv_in_get_local_type (MonoMarshalSpec *spec, guint8 *ldc_op /*out*/)
7205 {
7206 if (spec == NULL) {
7207 return &mono_defaults.int32_class->byval_arg;
7208 } else {
7209 switch (spec->native) {
7210 case MONO_NATIVE_I1:
7211 case MONO_NATIVE_U1:
7212 return &mono_defaults.byte_class->byval_arg;
7213 case MONO_NATIVE_VARIANTBOOL:
7214 if (ldc_op) *ldc_op = CEE_LDC_I4_M1;
7215 return &mono_defaults.int16_class->byval_arg;
7216 case MONO_NATIVE_BOOLEAN:
7217 return &mono_defaults.int32_class->byval_arg;
7218 default:
7219 g_warning ("marshalling bool as native type %x is currently not supported", spec->native);
7220 return &mono_defaults.int32_class->byval_arg;
7221 }
7222 }
7223 }
7224
7225 static MonoClass*
marshal_boolean_managed_conv_in_get_conv_arg_class(MonoMarshalSpec * spec,guint8 * ldop)7226 marshal_boolean_managed_conv_in_get_conv_arg_class (MonoMarshalSpec *spec, guint8 *ldop/*out*/)
7227 {
7228 MonoClass* conv_arg_class = mono_defaults.int32_class;
7229 if (spec) {
7230 switch (spec->native) {
7231 case MONO_NATIVE_I1:
7232 case MONO_NATIVE_U1:
7233 conv_arg_class = mono_defaults.byte_class;
7234 if (ldop) *ldop = CEE_LDIND_I1;
7235 break;
7236 case MONO_NATIVE_VARIANTBOOL:
7237 conv_arg_class = mono_defaults.int16_class;
7238 if (ldop) *ldop = CEE_LDIND_I2;
7239 break;
7240 case MONO_NATIVE_BOOLEAN:
7241 break;
7242 default:
7243 g_warning ("marshalling bool as native type %x is currently not supported", spec->native);
7244 }
7245 }
7246 return conv_arg_class;
7247 }
7248
7249 static int
emit_marshal_boolean(EmitMarshalContext * m,int argnum,MonoType * t,MonoMarshalSpec * spec,int conv_arg,MonoType ** conv_arg_type,MarshalAction action)7250 emit_marshal_boolean (EmitMarshalContext *m, int argnum, MonoType *t,
7251 MonoMarshalSpec *spec,
7252 int conv_arg, MonoType **conv_arg_type,
7253 MarshalAction action)
7254 {
7255 #ifndef ENABLE_ILGEN
7256 switch (action) {
7257 case MARSHAL_ACTION_CONV_IN:
7258 if (t->byref)
7259 *conv_arg_type = &mono_defaults.int_class->byval_arg;
7260 else
7261 *conv_arg_type = marshal_boolean_conv_in_get_local_type (spec, NULL);
7262 break;
7263
7264 case MARSHAL_ACTION_MANAGED_CONV_IN: {
7265 MonoClass* conv_arg_class = marshal_boolean_managed_conv_in_get_conv_arg_class (spec, NULL);
7266 if (t->byref)
7267 *conv_arg_type = &conv_arg_class->this_arg;
7268 else
7269 *conv_arg_type = &conv_arg_class->byval_arg;
7270 break;
7271 }
7272
7273 }
7274 #else
7275 MonoMethodBuilder *mb = m->mb;
7276
7277 switch (action) {
7278 case MARSHAL_ACTION_CONV_IN: {
7279 MonoType *local_type;
7280 int label_false;
7281 guint8 ldc_op = CEE_LDC_I4_1;
7282
7283 local_type = marshal_boolean_conv_in_get_local_type (spec, &ldc_op);
7284 if (t->byref)
7285 *conv_arg_type = &mono_defaults.int_class->byval_arg;
7286 else
7287 *conv_arg_type = local_type;
7288 conv_arg = mono_mb_add_local (mb, local_type);
7289
7290 mono_mb_emit_ldarg (mb, argnum);
7291 if (t->byref)
7292 mono_mb_emit_byte (mb, CEE_LDIND_I1);
7293 label_false = mono_mb_emit_branch (mb, CEE_BRFALSE);
7294 mono_mb_emit_byte (mb, ldc_op);
7295 mono_mb_emit_stloc (mb, conv_arg);
7296 mono_mb_patch_branch (mb, label_false);
7297
7298 break;
7299 }
7300
7301 case MARSHAL_ACTION_CONV_OUT:
7302 {
7303 int label_false, label_end;
7304 if (!t->byref)
7305 break;
7306
7307 mono_mb_emit_ldarg (mb, argnum);
7308 mono_mb_emit_ldloc (mb, conv_arg);
7309
7310 label_false = mono_mb_emit_branch (mb, CEE_BRFALSE);
7311 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
7312
7313 label_end = mono_mb_emit_branch (mb, CEE_BR);
7314 mono_mb_patch_branch (mb, label_false);
7315 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
7316 mono_mb_patch_branch (mb, label_end);
7317
7318 mono_mb_emit_byte (mb, CEE_STIND_I1);
7319 break;
7320 }
7321
7322 case MARSHAL_ACTION_PUSH:
7323 if (t->byref)
7324 mono_mb_emit_ldloc_addr (mb, conv_arg);
7325 else if (conv_arg)
7326 mono_mb_emit_ldloc (mb, conv_arg);
7327 else
7328 mono_mb_emit_ldarg (mb, argnum);
7329 break;
7330
7331 case MARSHAL_ACTION_CONV_RESULT:
7332 /* maybe we need to make sure that it fits within 8 bits */
7333 mono_mb_emit_stloc (mb, 3);
7334 break;
7335
7336 case MARSHAL_ACTION_MANAGED_CONV_IN: {
7337 MonoClass* conv_arg_class = mono_defaults.int32_class;
7338 guint8 ldop = CEE_LDIND_I4;
7339 int label_null, label_false;
7340
7341 conv_arg_class = marshal_boolean_managed_conv_in_get_conv_arg_class (spec, &ldop);
7342 conv_arg = mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
7343
7344 if (t->byref)
7345 *conv_arg_type = &conv_arg_class->this_arg;
7346 else
7347 *conv_arg_type = &conv_arg_class->byval_arg;
7348
7349
7350 mono_mb_emit_ldarg (mb, argnum);
7351
7352 /* Check null */
7353 if (t->byref) {
7354 label_null = mono_mb_emit_branch (mb, CEE_BRFALSE);
7355 mono_mb_emit_ldarg (mb, argnum);
7356 mono_mb_emit_byte (mb, ldop);
7357 } else
7358 label_null = 0;
7359
7360 label_false = mono_mb_emit_branch (mb, CEE_BRFALSE);
7361 mono_mb_emit_byte (mb, CEE_LDC_I4_1);
7362 mono_mb_emit_stloc (mb, conv_arg);
7363 mono_mb_patch_branch (mb, label_false);
7364
7365 if (t->byref)
7366 mono_mb_patch_branch (mb, label_null);
7367 break;
7368 }
7369
7370 case MARSHAL_ACTION_MANAGED_CONV_OUT: {
7371 guint8 stop = CEE_STIND_I4;
7372 guint8 ldc_op = CEE_LDC_I4_1;
7373 int label_null,label_false, label_end;;
7374
7375 if (!t->byref)
7376 break;
7377 if (spec) {
7378 switch (spec->native) {
7379 case MONO_NATIVE_I1:
7380 case MONO_NATIVE_U1:
7381 stop = CEE_STIND_I1;
7382 break;
7383 case MONO_NATIVE_VARIANTBOOL:
7384 stop = CEE_STIND_I2;
7385 ldc_op = CEE_LDC_I4_M1;
7386 break;
7387 default:
7388 break;
7389 }
7390 }
7391
7392 /* Check null */
7393 mono_mb_emit_ldarg (mb, argnum);
7394 label_null = mono_mb_emit_branch (mb, CEE_BRFALSE);
7395
7396 mono_mb_emit_ldarg (mb, argnum);
7397 mono_mb_emit_ldloc (mb, conv_arg);
7398
7399 label_false = mono_mb_emit_branch (mb, CEE_BRFALSE);
7400 mono_mb_emit_byte (mb, ldc_op);
7401 label_end = mono_mb_emit_branch (mb, CEE_BR);
7402
7403 mono_mb_patch_branch (mb, label_false);
7404 mono_mb_emit_byte (mb, CEE_LDC_I4_0);
7405 mono_mb_patch_branch (mb, label_end);
7406
7407 mono_mb_emit_byte (mb, stop);
7408 mono_mb_patch_branch (mb, label_null);
7409 break;
7410 }
7411
7412 default:
7413 g_assert_not_reached ();
7414 }
7415 #endif
7416 return conv_arg;
7417 }
7418
7419 static int
emit_marshal_ptr(EmitMarshalContext * m,int argnum,MonoType * t,MonoMarshalSpec * spec,int conv_arg,MonoType ** conv_arg_type,MarshalAction action)7420 emit_marshal_ptr (EmitMarshalContext *m, int argnum, MonoType *t,
7421 MonoMarshalSpec *spec, int conv_arg,
7422 MonoType **conv_arg_type, MarshalAction action)
7423 {
7424 #ifdef ENABLE_ILGEN
7425 MonoMethodBuilder *mb = m->mb;
7426
7427 switch (action) {
7428 case MARSHAL_ACTION_CONV_IN:
7429 /* MS seems to allow this in some cases, ie. bxc #158 */
7430 /*
7431 if (MONO_TYPE_ISSTRUCT (t->data.type) && !mono_class_from_mono_type (t->data.type)->blittable) {
7432 char *msg = g_strdup_printf ("Can not marshal 'parameter #%d': Pointers can not reference marshaled structures. Use byref instead.", argnum + 1);
7433 mono_mb_emit_exception_marshal_directive (m->mb, msg);
7434 }
7435 */
7436 break;
7437
7438 case MARSHAL_ACTION_PUSH:
7439 mono_mb_emit_ldarg (mb, argnum);
7440 break;
7441
7442 case MARSHAL_ACTION_CONV_RESULT:
7443 /* no conversions necessary */
7444 mono_mb_emit_stloc (mb, 3);
7445 break;
7446
7447 default:
7448 break;
7449 }
7450 #endif
7451 return conv_arg;
7452 }
7453
7454 static int
emit_marshal_char(EmitMarshalContext * m,int argnum,MonoType * t,MonoMarshalSpec * spec,int conv_arg,MonoType ** conv_arg_type,MarshalAction action)7455 emit_marshal_char (EmitMarshalContext *m, int argnum, MonoType *t,
7456 MonoMarshalSpec *spec, int conv_arg,
7457 MonoType **conv_arg_type, MarshalAction action)
7458 {
7459 #ifdef ENABLE_ILGEN
7460 MonoMethodBuilder *mb = m->mb;
7461
7462 switch (action) {
7463 case MARSHAL_ACTION_PUSH:
7464 /* fixme: dont know how to marshal that. We cant simply
7465 * convert it to a one byte UTF8 character, because an
7466 * unicode character may need more that one byte in UTF8 */
7467 mono_mb_emit_ldarg (mb, argnum);
7468 break;
7469
7470 case MARSHAL_ACTION_CONV_RESULT:
7471 /* fixme: we need conversions here */
7472 mono_mb_emit_stloc (mb, 3);
7473 break;
7474
7475 default:
7476 break;
7477 }
7478 #endif
7479 return conv_arg;
7480 }
7481
7482 static int
emit_marshal_scalar(EmitMarshalContext * m,int argnum,MonoType * t,MonoMarshalSpec * spec,int conv_arg,MonoType ** conv_arg_type,MarshalAction action)7483 emit_marshal_scalar (EmitMarshalContext *m, int argnum, MonoType *t,
7484 MonoMarshalSpec *spec, int conv_arg,
7485 MonoType **conv_arg_type, MarshalAction action)
7486 {
7487 #ifdef ENABLE_ILGEN
7488 MonoMethodBuilder *mb = m->mb;
7489
7490 switch (action) {
7491 case MARSHAL_ACTION_PUSH:
7492 mono_mb_emit_ldarg (mb, argnum);
7493 break;
7494
7495 case MARSHAL_ACTION_CONV_RESULT:
7496 /* no conversions necessary */
7497 mono_mb_emit_stloc (mb, 3);
7498 break;
7499
7500 default:
7501 break;
7502 }
7503 #endif
7504 return conv_arg;
7505 }
7506
7507 static int
emit_marshal(EmitMarshalContext * m,int argnum,MonoType * t,MonoMarshalSpec * spec,int conv_arg,MonoType ** conv_arg_type,MarshalAction action)7508 emit_marshal (EmitMarshalContext *m, int argnum, MonoType *t,
7509 MonoMarshalSpec *spec, int conv_arg,
7510 MonoType **conv_arg_type, MarshalAction action)
7511 {
7512 /* Ensure that we have marshalling info for this param */
7513 mono_marshal_load_type_info (mono_class_from_mono_type (t));
7514
7515 if (spec && spec->native == MONO_NATIVE_CUSTOM)
7516 return emit_marshal_custom (m, argnum, t, spec, conv_arg, conv_arg_type, action);
7517
7518 if (spec && spec->native == MONO_NATIVE_ASANY)
7519 return emit_marshal_asany (m, argnum, t, spec, conv_arg, conv_arg_type, action);
7520
7521 switch (t->type) {
7522 case MONO_TYPE_VALUETYPE:
7523 if (t->data.klass == mono_defaults.handleref_class)
7524 return emit_marshal_handleref (m, argnum, t, spec, conv_arg, conv_arg_type, action);
7525
7526 return emit_marshal_vtype (m, argnum, t, spec, conv_arg, conv_arg_type, action);
7527 case MONO_TYPE_STRING:
7528 return emit_marshal_string (m, argnum, t, spec, conv_arg, conv_arg_type, action);
7529 case MONO_TYPE_CLASS:
7530 case MONO_TYPE_OBJECT:
7531 #if !defined(DISABLE_COM) && defined(ENABLE_ILGEN)
7532 if (spec && spec->native == MONO_NATIVE_STRUCT)
7533 return emit_marshal_variant (m, argnum, t, spec, conv_arg, conv_arg_type, action);
7534 #endif
7535
7536 #if !defined(DISABLE_COM)
7537 if (spec && (spec->native == MONO_NATIVE_IUNKNOWN ||
7538 spec->native == MONO_NATIVE_IDISPATCH ||
7539 spec->native == MONO_NATIVE_INTERFACE))
7540 return mono_cominterop_emit_marshal_com_interface (m, argnum, t, spec, conv_arg, conv_arg_type, action);
7541 if (spec && (spec->native == MONO_NATIVE_SAFEARRAY) &&
7542 (spec->data.safearray_data.elem_type == MONO_VARIANT_VARIANT) &&
7543 ((action == MARSHAL_ACTION_CONV_OUT) || (action == MARSHAL_ACTION_CONV_IN) || (action == MARSHAL_ACTION_PUSH)))
7544 return mono_cominterop_emit_marshal_safearray (m, argnum, t, spec, conv_arg, conv_arg_type, action);
7545 #endif
7546
7547 if (mono_class_try_get_safehandle_class () != NULL && t->data.klass &&
7548 mono_class_is_subclass_of (t->data.klass, mono_class_try_get_safehandle_class (), FALSE))
7549 return emit_marshal_safehandle (m, argnum, t, spec, conv_arg, conv_arg_type, action);
7550
7551 return emit_marshal_object (m, argnum, t, spec, conv_arg, conv_arg_type, action);
7552 case MONO_TYPE_ARRAY:
7553 case MONO_TYPE_SZARRAY:
7554 return emit_marshal_array (m, argnum, t, spec, conv_arg, conv_arg_type, action);
7555 case MONO_TYPE_BOOLEAN:
7556 return emit_marshal_boolean (m, argnum, t, spec, conv_arg, conv_arg_type, action);
7557 case MONO_TYPE_PTR:
7558 return emit_marshal_ptr (m, argnum, t, spec, conv_arg, conv_arg_type, action);
7559 case MONO_TYPE_CHAR:
7560 return emit_marshal_char (m, argnum, t, spec, conv_arg, conv_arg_type, action);
7561 case MONO_TYPE_I1:
7562 case MONO_TYPE_U1:
7563 case MONO_TYPE_I2:
7564 case MONO_TYPE_U2:
7565 case MONO_TYPE_I4:
7566 case MONO_TYPE_U4:
7567 case MONO_TYPE_I:
7568 case MONO_TYPE_U:
7569 case MONO_TYPE_R4:
7570 case MONO_TYPE_R8:
7571 case MONO_TYPE_I8:
7572 case MONO_TYPE_U8:
7573 case MONO_TYPE_FNPTR:
7574 return emit_marshal_scalar (m, argnum, t, spec, conv_arg, conv_arg_type, action);
7575 case MONO_TYPE_GENERICINST:
7576 if (mono_type_generic_inst_is_valuetype (t))
7577 return emit_marshal_vtype (m, argnum, t, spec, conv_arg, conv_arg_type, action);
7578 else
7579 return emit_marshal_object (m, argnum, t, spec, conv_arg, conv_arg_type, action);
7580 default:
7581 return conv_arg;
7582 }
7583 }
7584
7585 /* How the arguments of an icall should be wrapped */
7586 typedef enum {
7587 /* Don't wrap at all, pass the argument as is */
7588 ICALL_HANDLES_WRAP_NONE,
7589 /* Wrap the argument in an object handle, pass the handle to the icall */
7590 ICALL_HANDLES_WRAP_OBJ,
7591 /* Wrap the argument in an object handle, pass the handle to the icall,
7592 write the value out from the handle when the icall returns */
7593 ICALL_HANDLES_WRAP_OBJ_INOUT,
7594 /* Initialized an object handle to null, pass to the icalls,
7595 write the value out from the handle when the icall returns */
7596 ICALL_HANDLES_WRAP_OBJ_OUT,
7597 /* Wrap the argument (a valuetype reference) in a handle to pin its enclosing object,
7598 but pass the raw reference to the icall */
7599 ICALL_HANDLES_WRAP_VALUETYPE_REF,
7600 } IcallHandlesWrap;
7601
7602 typedef struct {
7603 IcallHandlesWrap wrap;
7604 /* if wrap is NONE or OBJ or VALUETYPE_REF, this is not meaningful.
7605 if wrap is OBJ_INOUT it's the local var that holds the MonoObjectHandle.
7606 */
7607 int handle;
7608 } IcallHandlesLocal;
7609
7610 /*
7611 * Describes how to wrap the given parameter.
7612 *
7613 */
7614 static IcallHandlesWrap
signature_param_uses_handles(MonoMethodSignature * sig,int param)7615 signature_param_uses_handles (MonoMethodSignature *sig, int param)
7616 {
7617 if (MONO_TYPE_IS_REFERENCE (sig->params [param])) {
7618 if (mono_signature_param_is_out (sig, param))
7619 return ICALL_HANDLES_WRAP_OBJ_OUT;
7620 else if (mono_type_is_byref (sig->params [param]))
7621 return ICALL_HANDLES_WRAP_OBJ_INOUT;
7622 else
7623 return ICALL_HANDLES_WRAP_OBJ;
7624 } else if (mono_type_is_byref (sig->params [param]))
7625 return ICALL_HANDLES_WRAP_VALUETYPE_REF;
7626 else
7627 return ICALL_HANDLES_WRAP_NONE;
7628 }
7629
7630
7631 #ifdef ENABLE_ILGEN
7632 /**
7633 * mono_marshal_emit_native_wrapper:
7634 * \param image the image to use for looking up custom marshallers
7635 * \param sig The signature of the native function
7636 * \param piinfo Marshalling information
7637 * \param mspecs Marshalling information
7638 * \param aot whenever the created method will be compiled by the AOT compiler
7639 * \param method if non-NULL, the pinvoke method to call
7640 * \param check_exceptions Whenever to check for pending exceptions after the native call
7641 * \param func_param the function to call is passed as a boxed IntPtr as the first parameter
7642 *
7643 * generates IL code for the pinvoke wrapper, the generated code calls \p func .
7644 */
7645 void
mono_marshal_emit_native_wrapper(MonoImage * image,MonoMethodBuilder * mb,MonoMethodSignature * sig,MonoMethodPInvoke * piinfo,MonoMarshalSpec ** mspecs,gpointer func,gboolean aot,gboolean check_exceptions,gboolean func_param)7646 mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func, gboolean aot, gboolean check_exceptions, gboolean func_param)
7647 {
7648 EmitMarshalContext m;
7649 MonoMethodSignature *csig;
7650 MonoClass *klass;
7651 int i, argnum, *tmp_locals;
7652 int type, param_shift = 0;
7653 int coop_gc_stack_dummy, coop_gc_var;
7654 #ifndef DISABLE_COM
7655 int coop_cominterop_fnptr;
7656 #endif
7657
7658 memset (&m, 0, sizeof (m));
7659 m.mb = mb;
7660 m.sig = sig;
7661 m.piinfo = piinfo;
7662
7663 /* we copy the signature, so that we can set pinvoke to 0 */
7664 if (func_param) {
7665 /* The function address is passed as the first argument */
7666 g_assert (!sig->hasthis);
7667 param_shift += 1;
7668 }
7669 csig = mono_metadata_signature_dup_full (mb->method->klass->image, sig);
7670 csig->pinvoke = 1;
7671 m.csig = csig;
7672 m.image = image;
7673
7674 if (sig->hasthis)
7675 param_shift += 1;
7676
7677 /* we allocate local for use with emit_struct_conv() */
7678 /* allocate local 0 (pointer) src_ptr */
7679 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7680 /* allocate local 1 (pointer) dst_ptr */
7681 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7682 /* allocate local 2 (boolean) delete_old */
7683 mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
7684
7685 /* delete_old = FALSE */
7686 mono_mb_emit_icon (mb, 0);
7687 mono_mb_emit_stloc (mb, 2);
7688
7689 if (!MONO_TYPE_IS_VOID (sig->ret)) {
7690 /* allocate local 3 to store the return value */
7691 mono_mb_add_local (mb, sig->ret);
7692 }
7693
7694 if (mono_threads_is_blocking_transition_enabled ()) {
7695 /* local 4, dummy local used to get a stack address for suspend funcs */
7696 coop_gc_stack_dummy = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7697 /* local 5, the local to be used when calling the suspend funcs */
7698 coop_gc_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7699 #ifndef DISABLE_COM
7700 if (!func_param && MONO_CLASS_IS_IMPORT (mb->method->klass)) {
7701 coop_cominterop_fnptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7702 }
7703 #endif
7704 }
7705
7706 /*
7707 * cookie = mono_threads_enter_gc_safe_region_unbalanced (ref dummy);
7708 *
7709 * ret = method (...);
7710 *
7711 * mono_threads_exit_gc_safe_region_unbalanced (cookie, ref dummy);
7712 *
7713 * <interrupt check>
7714 *
7715 * return ret;
7716 */
7717
7718 if (MONO_TYPE_ISSTRUCT (sig->ret))
7719 m.vtaddr_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
7720
7721 if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
7722 /* Return type custom marshaling */
7723 /*
7724 * Since we can't determine the return type of the unmanaged function,
7725 * we assume it returns a pointer, and pass that pointer to
7726 * MarshalNativeToManaged.
7727 */
7728 csig->ret = &mono_defaults.int_class->byval_arg;
7729 }
7730
7731 /* we first do all conversions */
7732 tmp_locals = (int *)alloca (sizeof (int) * sig->param_count);
7733 m.orig_conv_args = (int *)alloca (sizeof (int) * (sig->param_count + 1));
7734
7735 for (i = 0; i < sig->param_count; i ++) {
7736 tmp_locals [i] = emit_marshal (&m, i + param_shift, sig->params [i], mspecs [i + 1], 0, &csig->params [i], MARSHAL_ACTION_CONV_IN);
7737 }
7738
7739 // In coop mode need to register blocking state during native call
7740 if (mono_threads_is_blocking_transition_enabled ()) {
7741 // Perform an extra, early lookup of the function address, so any exceptions
7742 // potentially resulting from the lookup occur before entering blocking mode.
7743 if (!func_param && !MONO_CLASS_IS_IMPORT (mb->method->klass) && aot) {
7744 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
7745 mono_mb_emit_op (mb, CEE_MONO_ICALL_ADDR, &piinfo->method);
7746 mono_mb_emit_byte (mb, CEE_POP); // Result not needed yet
7747 }
7748
7749 #ifndef DISABLE_COM
7750 if (!func_param && MONO_CLASS_IS_IMPORT (mb->method->klass)) {
7751 mono_mb_emit_cominterop_get_function_pointer (mb, &piinfo->method);
7752 mono_mb_emit_stloc (mb, coop_cominterop_fnptr);
7753 }
7754 #endif
7755
7756 mono_mb_emit_ldloc_addr (mb, coop_gc_stack_dummy);
7757 mono_mb_emit_icall (mb, mono_threads_enter_gc_safe_region_unbalanced);
7758 mono_mb_emit_stloc (mb, coop_gc_var);
7759 }
7760
7761 /* push all arguments */
7762
7763 if (sig->hasthis)
7764 mono_mb_emit_byte (mb, CEE_LDARG_0);
7765
7766 for (i = 0; i < sig->param_count; i++) {
7767 emit_marshal (&m, i + param_shift, sig->params [i], mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_PUSH);
7768 }
7769
7770 /* call the native method */
7771 if (func_param) {
7772 mono_mb_emit_byte (mb, CEE_LDARG_0);
7773 mono_mb_emit_op (mb, CEE_UNBOX, mono_defaults.int_class);
7774 mono_mb_emit_byte (mb, CEE_LDIND_I);
7775 mono_mb_emit_calli (mb, csig);
7776 } else if (MONO_CLASS_IS_IMPORT (mb->method->klass)) {
7777 #ifndef DISABLE_COM
7778 if (!mono_threads_is_blocking_transition_enabled ()) {
7779 mono_mb_emit_cominterop_call (mb, csig, &piinfo->method);
7780 } else {
7781 mono_mb_emit_ldloc (mb, coop_cominterop_fnptr);
7782 mono_mb_emit_cominterop_call_function_pointer (mb, csig);
7783 }
7784 #else
7785 g_assert_not_reached ();
7786 #endif
7787 } else {
7788 if (aot) {
7789 /* Reuse the ICALL_ADDR opcode for pinvokes too */
7790 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
7791 mono_mb_emit_op (mb, CEE_MONO_ICALL_ADDR, &piinfo->method);
7792 mono_mb_emit_calli (mb, csig);
7793 } else {
7794 mono_mb_emit_native_call (mb, csig, func);
7795 }
7796 }
7797
7798 /* Set LastError if needed */
7799 if (piinfo->piflags & PINVOKE_ATTRIBUTE_SUPPORTS_LAST_ERROR) {
7800 #ifdef TARGET_WIN32
7801 if (!aot) {
7802 static MonoMethodSignature *get_last_error_sig = NULL;
7803 if (!get_last_error_sig) {
7804 get_last_error_sig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
7805 get_last_error_sig->ret = &mono_defaults.int_class->byval_arg;
7806 get_last_error_sig->pinvoke = 1;
7807 }
7808
7809 /*
7810 * Have to call GetLastError () early and without a wrapper, since various runtime components could
7811 * clobber its value.
7812 */
7813 mono_mb_emit_native_call (mb, get_last_error_sig, GetLastError);
7814 mono_mb_emit_icall (mb, mono_marshal_set_last_error_windows);
7815 } else {
7816 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
7817 mono_mb_emit_byte (mb, CEE_MONO_GET_LAST_ERROR);
7818 mono_mb_emit_icall (mb, mono_marshal_set_last_error_windows);
7819 }
7820 #else
7821 mono_mb_emit_icall (mb, mono_marshal_set_last_error);
7822 #endif
7823 }
7824
7825 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
7826 MonoClass *klass = mono_class_from_mono_type (sig->ret);
7827 mono_class_init (klass);
7828 if (!(mono_class_is_explicit_layout (klass) || klass->blittable)) {
7829 /* This is used by emit_marshal_vtype (), but it needs to go right before the call */
7830 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
7831 mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
7832 mono_mb_emit_stloc (mb, m.vtaddr_var);
7833 }
7834 }
7835
7836 /* Unblock before converting the result, since that can involve calls into the runtime */
7837 if (mono_threads_is_blocking_transition_enabled ()) {
7838 mono_mb_emit_ldloc (mb, coop_gc_var);
7839 mono_mb_emit_ldloc_addr (mb, coop_gc_stack_dummy);
7840 mono_mb_emit_icall (mb, mono_threads_exit_gc_safe_region_unbalanced);
7841 }
7842
7843 /* convert the result */
7844 if (!sig->ret->byref) {
7845 MonoMarshalSpec *spec = mspecs [0];
7846 type = sig->ret->type;
7847
7848 if (spec && spec->native == MONO_NATIVE_CUSTOM) {
7849 emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
7850 } else {
7851 handle_enum:
7852 switch (type) {
7853 case MONO_TYPE_VOID:
7854 break;
7855 case MONO_TYPE_VALUETYPE:
7856 klass = sig->ret->data.klass;
7857 if (klass->enumtype) {
7858 type = mono_class_enum_basetype (sig->ret->data.klass)->type;
7859 goto handle_enum;
7860 }
7861 emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
7862 break;
7863 case MONO_TYPE_I1:
7864 case MONO_TYPE_U1:
7865 case MONO_TYPE_I2:
7866 case MONO_TYPE_U2:
7867 case MONO_TYPE_I4:
7868 case MONO_TYPE_U4:
7869 case MONO_TYPE_I:
7870 case MONO_TYPE_U:
7871 case MONO_TYPE_R4:
7872 case MONO_TYPE_R8:
7873 case MONO_TYPE_I8:
7874 case MONO_TYPE_U8:
7875 case MONO_TYPE_FNPTR:
7876 case MONO_TYPE_STRING:
7877 case MONO_TYPE_CLASS:
7878 case MONO_TYPE_OBJECT:
7879 case MONO_TYPE_BOOLEAN:
7880 case MONO_TYPE_ARRAY:
7881 case MONO_TYPE_SZARRAY:
7882 case MONO_TYPE_CHAR:
7883 case MONO_TYPE_PTR:
7884 case MONO_TYPE_GENERICINST:
7885 emit_marshal (&m, 0, sig->ret, spec, 0, NULL, MARSHAL_ACTION_CONV_RESULT);
7886 break;
7887 case MONO_TYPE_TYPEDBYREF:
7888 default:
7889 g_warning ("return type 0x%02x unknown", sig->ret->type);
7890 g_assert_not_reached ();
7891 }
7892 }
7893 } else {
7894 mono_mb_emit_stloc (mb, 3);
7895 }
7896
7897 /*
7898 * Need to call this after converting the result since MONO_VTADDR needs
7899 * to be adjacent to the call instruction.
7900 */
7901 if (check_exceptions)
7902 emit_thread_interrupt_checkpoint (mb);
7903
7904 /* we need to convert byref arguments back and free string arrays */
7905 for (i = 0; i < sig->param_count; i++) {
7906 MonoType *t = sig->params [i];
7907 MonoMarshalSpec *spec = mspecs [i + 1];
7908
7909 argnum = i + param_shift;
7910
7911 if (spec && ((spec->native == MONO_NATIVE_CUSTOM) || (spec->native == MONO_NATIVE_ASANY))) {
7912 emit_marshal (&m, argnum, t, spec, tmp_locals [i], NULL, MARSHAL_ACTION_CONV_OUT);
7913 continue;
7914 }
7915
7916 switch (t->type) {
7917 case MONO_TYPE_STRING:
7918 case MONO_TYPE_VALUETYPE:
7919 case MONO_TYPE_CLASS:
7920 case MONO_TYPE_OBJECT:
7921 case MONO_TYPE_SZARRAY:
7922 case MONO_TYPE_BOOLEAN:
7923 emit_marshal (&m, argnum, t, spec, tmp_locals [i], NULL, MARSHAL_ACTION_CONV_OUT);
7924 break;
7925 default:
7926 break;
7927 }
7928 }
7929
7930 if (!MONO_TYPE_IS_VOID(sig->ret))
7931 mono_mb_emit_ldloc (mb, 3);
7932
7933 mono_mb_emit_byte (mb, CEE_RET);
7934 }
7935 #endif /* ENABLE_ILGEN */
7936
7937 /**
7938 * mono_marshal_get_native_wrapper:
7939 * \param method The \c MonoMethod to wrap.
7940 * \param check_exceptions Whenever to check for pending exceptions
7941 *
7942 * Generates IL code for the pinvoke wrapper. The generated method
7943 * calls the unmanaged code in \c piinfo->addr.
7944 */
7945 MonoMethod *
mono_marshal_get_native_wrapper(MonoMethod * method,gboolean check_exceptions,gboolean aot)7946 mono_marshal_get_native_wrapper (MonoMethod *method, gboolean check_exceptions, gboolean aot)
7947 {
7948 MonoMethodSignature *sig, *csig;
7949 MonoMethodPInvoke *piinfo = (MonoMethodPInvoke *) method;
7950 MonoMethodBuilder *mb;
7951 MonoMarshalSpec **mspecs;
7952 MonoMethod *res;
7953 GHashTable *cache;
7954 gboolean pinvoke = FALSE;
7955 gpointer iter;
7956 int i;
7957 const char *exc_class = "MissingMethodException";
7958 const char *exc_arg = NULL;
7959 WrapperInfo *info;
7960
7961 g_assert (method != NULL);
7962 g_assert (mono_method_signature (method)->pinvoke);
7963
7964 GHashTable **cache_ptr;
7965
7966 if (aot) {
7967 if (check_exceptions)
7968 cache_ptr = &mono_method_get_wrapper_cache (method)->native_wrapper_aot_check_cache;
7969 else
7970 cache_ptr = &mono_method_get_wrapper_cache (method)->native_wrapper_aot_cache;
7971 } else {
7972 if (check_exceptions)
7973 cache_ptr = &mono_method_get_wrapper_cache (method)->native_wrapper_check_cache;
7974 else
7975 cache_ptr = &mono_method_get_wrapper_cache (method)->native_wrapper_cache;
7976 }
7977
7978 cache = get_cache (cache_ptr, mono_aligned_addr_hash, NULL);
7979
7980 if ((res = mono_marshal_find_in_cache (cache, method)))
7981 return res;
7982
7983 if (MONO_CLASS_IS_IMPORT (method->klass)) {
7984 /* The COM code is not AOT compatible, it calls mono_custom_attrs_get_attr_checked () */
7985 if (aot)
7986 return method;
7987 #ifndef DISABLE_COM
7988 return mono_cominterop_get_native_wrapper (method);
7989 #else
7990 g_assert_not_reached ();
7991 #endif
7992 }
7993
7994 sig = mono_method_signature (method);
7995
7996 if (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) &&
7997 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
7998 pinvoke = TRUE;
7999
8000 if (!piinfo->addr) {
8001 if (pinvoke) {
8002 if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)
8003 exc_arg = "Method contains unsupported native code";
8004 else if (!aot)
8005 mono_lookup_pinvoke_call (method, &exc_class, &exc_arg);
8006 } else {
8007 piinfo->addr = mono_lookup_internal_call (method);
8008 }
8009 }
8010
8011 /* hack - redirect certain string constructors to CreateString */
8012 if (piinfo->addr == ves_icall_System_String_ctor_RedirectToCreateString) {
8013 g_assert (!pinvoke);
8014 g_assert (method->string_ctor);
8015 g_assert (sig->hasthis);
8016
8017 /* CreateString returns a value */
8018 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
8019 csig->ret = &mono_defaults.string_class->byval_arg;
8020 csig->pinvoke = 0;
8021
8022 iter = NULL;
8023 while ((res = mono_class_get_methods (mono_defaults.string_class, &iter))) {
8024 if (!strcmp ("CreateString", res->name) &&
8025 mono_metadata_signature_equal (csig, mono_method_signature (res))) {
8026 WrapperInfo *info;
8027
8028 g_assert (!(res->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL));
8029 g_assert (!(res->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL));
8030
8031 /* create a wrapper to preserve .ctor in stack trace */
8032 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_MANAGED);
8033
8034 #ifdef ENABLE_ILGEN
8035 mono_mb_emit_byte (mb, CEE_LDARG_0);
8036 for (i = 1; i <= csig->param_count; i++)
8037 mono_mb_emit_ldarg (mb, i);
8038 mono_mb_emit_managed_call (mb, res, NULL);
8039 mono_mb_emit_byte (mb, CEE_RET);
8040 #endif
8041
8042 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_STRING_CTOR);
8043 info->d.string_ctor.method = method;
8044
8045 /* use native_wrapper_cache because internal calls are looked up there */
8046 res = mono_mb_create_and_cache_full (cache, method, mb, csig,
8047 csig->param_count + 1, info, NULL);
8048 mono_mb_free (mb);
8049
8050 return res;
8051 }
8052 }
8053
8054 /* exception will be thrown */
8055 piinfo->addr = NULL;
8056 g_warning ("cannot find CreateString for .ctor");
8057 }
8058
8059 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_NATIVE);
8060
8061 mb->method->save_lmf = 1;
8062
8063 /*
8064 * In AOT mode and embedding scenarios, it is possible that the icall is not
8065 * registered in the runtime doing the AOT compilation.
8066 */
8067 if (!piinfo->addr && !aot) {
8068 #ifdef ENABLE_ILGEN
8069 mono_mb_emit_exception (mb, exc_class, exc_arg);
8070 #endif
8071 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NONE);
8072 info->d.managed_to_native.method = method;
8073
8074 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
8075 csig->pinvoke = 0;
8076 res = mono_mb_create_and_cache_full (cache, method, mb, csig,
8077 csig->param_count + 16, info, NULL);
8078 mono_mb_free (mb);
8079
8080 return res;
8081 }
8082
8083 /* internal calls: we simply push all arguments and call the method (no conversions) */
8084 if (method->iflags & (METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL | METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
8085 if (sig->hasthis)
8086 csig = mono_metadata_signature_dup_add_this (method->klass->image, sig, method->klass);
8087 else
8088 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
8089
8090 //printf ("%s\n", mono_method_full_name (method, 1));
8091
8092 /* hack - string constructors returns a value */
8093 if (method->string_ctor)
8094 csig->ret = &mono_defaults.string_class->byval_arg;
8095
8096 #ifdef ENABLE_ILGEN
8097 // FIXME:
8098 MonoClass *handle_stack_mark_class;
8099 MonoClass *error_class;
8100 int thread_info_var = -1, stack_mark_var = -1, error_var = -1;
8101 MonoMethodSignature *call_sig = csig;
8102 gboolean uses_handles = FALSE;
8103 gboolean save_handles_to_locals = FALSE;
8104 IcallHandlesLocal *handles_locals = NULL;
8105
8106 (void) mono_lookup_internal_call_full (method, &uses_handles);
8107
8108 /* If it uses handles and MonoError, it had better check exceptions */
8109 g_assert (!uses_handles || check_exceptions);
8110
8111 if (uses_handles) {
8112 MonoMethodSignature *ret;
8113
8114 /* Add a MonoError argument and figure out which args need to be wrapped in handles */
8115 // FIXME: The stuff from mono_metadata_signature_dup_internal_with_padding ()
8116 ret = mono_metadata_signature_alloc (method->klass->image, csig->param_count + 1);
8117
8118 ret->param_count = csig->param_count + 1;
8119 ret->ret = csig->ret;
8120
8121 handles_locals = g_new0 (IcallHandlesLocal, csig->param_count);
8122 for (int i = 0; i < csig->param_count; ++i) {
8123 IcallHandlesWrap w = signature_param_uses_handles (csig, i);
8124 handles_locals [i].wrap = w;
8125 switch (w) {
8126 case ICALL_HANDLES_WRAP_OBJ:
8127 case ICALL_HANDLES_WRAP_OBJ_INOUT:
8128 case ICALL_HANDLES_WRAP_OBJ_OUT:
8129 ret->params [i] = mono_class_get_byref_type (mono_class_from_mono_type(csig->params[i]));
8130 if (w == ICALL_HANDLES_WRAP_OBJ_OUT || w == ICALL_HANDLES_WRAP_OBJ_INOUT)
8131 save_handles_to_locals = TRUE;
8132 break;
8133 case ICALL_HANDLES_WRAP_NONE:
8134 case ICALL_HANDLES_WRAP_VALUETYPE_REF:
8135 ret->params [i] = csig->params [i];
8136 break;
8137 default:
8138 g_assert_not_reached ();
8139 }
8140 }
8141 /* Add MonoError* param */
8142 ret->params [csig->param_count] = &mono_get_intptr_class ()->byval_arg;
8143 ret->pinvoke = csig->pinvoke;
8144
8145 call_sig = ret;
8146 }
8147
8148 if (uses_handles) {
8149 handle_stack_mark_class = mono_class_load_from_name (mono_get_corlib (), "Mono", "RuntimeStructs/HandleStackMark");
8150 error_class = mono_class_load_from_name (mono_get_corlib (), "Mono", "RuntimeStructs/MonoError");
8151
8152 thread_info_var = mono_mb_add_local (mb, &mono_get_intptr_class ()->byval_arg);
8153 stack_mark_var = mono_mb_add_local (mb, &handle_stack_mark_class->byval_arg);
8154 error_var = mono_mb_add_local (mb, &error_class->byval_arg);
8155
8156 if (save_handles_to_locals) {
8157 /* add a local var to hold the handles for each out arg */
8158 for (int i = 0; i < sig->param_count; ++i) {
8159 int j = i + sig->hasthis;
8160 switch (handles_locals[j].wrap) {
8161 case ICALL_HANDLES_WRAP_NONE:
8162 case ICALL_HANDLES_WRAP_OBJ:
8163 case ICALL_HANDLES_WRAP_VALUETYPE_REF:
8164 handles_locals [j].handle = -1;
8165 break;
8166 case ICALL_HANDLES_WRAP_OBJ_INOUT:
8167 case ICALL_HANDLES_WRAP_OBJ_OUT:
8168 handles_locals [j].handle = mono_mb_add_local (mb, sig->params [i]);
8169 break;
8170 default:
8171 g_assert_not_reached ();
8172 }
8173 }
8174 }
8175 }
8176
8177 if (sig->hasthis) {
8178 int pos;
8179
8180 /*
8181 * Add a null check since public icalls can be called with 'call' which
8182 * does no such check.
8183 */
8184 mono_mb_emit_byte (mb, CEE_LDARG_0);
8185 pos = mono_mb_emit_branch (mb, CEE_BRTRUE);
8186 mono_mb_emit_exception (mb, "NullReferenceException", NULL);
8187 mono_mb_patch_branch (mb, pos);
8188 }
8189
8190 if (uses_handles) {
8191 mono_mb_emit_ldloc_addr (mb, stack_mark_var);
8192 mono_mb_emit_ldloc_addr (mb, error_var);
8193 mono_mb_emit_icall (mb, mono_icall_start);
8194 mono_mb_emit_stloc (mb, thread_info_var);
8195
8196 if (sig->hasthis) {
8197 mono_mb_emit_byte (mb, CEE_LDARG_0);
8198 /* TODO support adding wrappers to non-static struct methods */
8199 g_assert (!mono_class_is_valuetype(mono_method_get_class (method)));
8200 mono_mb_emit_icall (mb, mono_icall_handle_new);
8201 }
8202 for (i = 0; i < sig->param_count; i++) {
8203 /* load each argument. references into the managed heap get wrapped in handles */
8204 int j = i + sig->hasthis;
8205 switch (handles_locals[j].wrap) {
8206 case ICALL_HANDLES_WRAP_NONE:
8207 mono_mb_emit_ldarg (mb, j);
8208 break;
8209 case ICALL_HANDLES_WRAP_OBJ:
8210 /* argI = mono_handle_new (argI_raw) */
8211 mono_mb_emit_ldarg (mb, j);
8212 mono_mb_emit_icall (mb, mono_icall_handle_new);
8213 break;
8214 case ICALL_HANDLES_WRAP_OBJ_INOUT:
8215 case ICALL_HANDLES_WRAP_OBJ_OUT:
8216 /* if inout:
8217 * handleI = argI = mono_handle_new (*argI_raw)
8218 * otherwise:
8219 * handleI = argI = mono_handle_new (NULL)
8220 */
8221 if (handles_locals[j].wrap == ICALL_HANDLES_WRAP_OBJ_INOUT) {
8222 mono_mb_emit_ldarg (mb, j);
8223 mono_mb_emit_byte (mb, CEE_LDIND_REF);
8224 } else
8225 mono_mb_emit_byte (mb, CEE_LDNULL);
8226 mono_mb_emit_icall (mb, mono_icall_handle_new);
8227 /* tmp = argI */
8228 mono_mb_emit_byte (mb, CEE_DUP);
8229 /* handleI = tmp */
8230 mono_mb_emit_stloc (mb, handles_locals[j].handle);
8231 break;
8232 case ICALL_HANDLES_WRAP_VALUETYPE_REF:
8233 /* (void) mono_handle_new (argI); argI */
8234 mono_mb_emit_ldarg (mb, j);
8235 mono_mb_emit_byte (mb, CEE_DUP);
8236 mono_mb_emit_icall (mb, mono_icall_handle_new_interior);
8237 mono_mb_emit_byte (mb, CEE_POP);
8238 #if 0
8239 fprintf (stderr, " Method %s.%s.%s has byref valuetype argument %d\n", method->klass->name_space, method->klass->name, method->name, i);
8240 #endif
8241 break;
8242 default:
8243 g_assert_not_reached ();
8244 }
8245 }
8246 mono_mb_emit_ldloc_addr (mb, error_var);
8247 } else {
8248 if (sig->hasthis)
8249 mono_mb_emit_byte (mb, CEE_LDARG_0);
8250 for (i = 0; i < sig->param_count; i++)
8251 mono_mb_emit_ldarg (mb, i + sig->hasthis);
8252 }
8253
8254 if (aot) {
8255 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
8256 mono_mb_emit_op (mb, CEE_MONO_ICALL_ADDR, &piinfo->method);
8257 mono_mb_emit_calli (mb, call_sig);
8258 } else {
8259 g_assert (piinfo->addr);
8260 mono_mb_emit_native_call (mb, call_sig, piinfo->addr);
8261 }
8262
8263 if (uses_handles) {
8264 if (MONO_TYPE_IS_REFERENCE (sig->ret)) {
8265 // if (ret != NULL_HANDLE) {
8266 // ret = MONO_HANDLE_RAW(ret)
8267 // }
8268 mono_mb_emit_byte (mb, CEE_DUP);
8269 int pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
8270 mono_mb_emit_ldflda (mb, MONO_HANDLE_PAYLOAD_OFFSET (MonoObject));
8271 mono_mb_emit_byte (mb, CEE_LDIND_REF);
8272 mono_mb_patch_branch (mb, pos);
8273 }
8274 if (save_handles_to_locals) {
8275 for (i = 0; i < sig->param_count; i++) {
8276 int j = i + sig->hasthis;
8277 switch (handles_locals [j].wrap) {
8278 case ICALL_HANDLES_WRAP_NONE:
8279 case ICALL_HANDLES_WRAP_OBJ:
8280 case ICALL_HANDLES_WRAP_VALUETYPE_REF:
8281 break;
8282 case ICALL_HANDLES_WRAP_OBJ_INOUT:
8283 case ICALL_HANDLES_WRAP_OBJ_OUT:
8284 /* *argI_raw = MONO_HANDLE_RAW (handleI) */
8285
8286 /* argI_raw */
8287 mono_mb_emit_ldarg (mb, j);
8288 /* handleI */
8289 mono_mb_emit_ldloc (mb, handles_locals [j].handle);
8290 /* MONO_HANDLE_RAW(handleI) */
8291 mono_mb_emit_ldflda (mb, MONO_HANDLE_PAYLOAD_OFFSET (MonoObject));
8292 mono_mb_emit_byte (mb, CEE_LDIND_REF);
8293 /* *argI_raw = MONO_HANDLE_RAW(handleI) */
8294 mono_mb_emit_byte (mb, CEE_STIND_REF);
8295 break;
8296 default:
8297 g_assert_not_reached ();
8298 }
8299 }
8300 }
8301 g_free (handles_locals);
8302
8303 mono_mb_emit_ldloc (mb, thread_info_var);
8304 mono_mb_emit_ldloc_addr (mb, stack_mark_var);
8305 mono_mb_emit_ldloc_addr (mb, error_var);
8306 mono_mb_emit_icall (mb, mono_icall_end);
8307 }
8308
8309 if (check_exceptions)
8310 emit_thread_interrupt_checkpoint (mb);
8311 mono_mb_emit_byte (mb, CEE_RET);
8312 #endif
8313 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NONE);
8314 info->d.managed_to_native.method = method;
8315
8316 csig = mono_metadata_signature_dup_full (method->klass->image, csig);
8317 csig->pinvoke = 0;
8318 res = mono_mb_create_and_cache_full (cache, method, mb, csig, csig->param_count + 16,
8319 info, NULL);
8320
8321 mono_mb_free (mb);
8322 return res;
8323 }
8324
8325 g_assert (pinvoke);
8326 if (!aot)
8327 g_assert (piinfo->addr);
8328
8329 #ifdef ENABLE_ILGEN
8330 mspecs = g_new (MonoMarshalSpec*, sig->param_count + 1);
8331 mono_method_get_marshal_info (method, mspecs);
8332
8333 mono_marshal_emit_native_wrapper (mb->method->klass->image, mb, sig, piinfo, mspecs, piinfo->addr, aot, check_exceptions, FALSE);
8334 #endif
8335 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_PINVOKE);
8336 info->d.managed_to_native.method = method;
8337
8338 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
8339 csig->pinvoke = 0;
8340 res = mono_mb_create_and_cache_full (cache, method, mb, csig, csig->param_count + 16,
8341 info, NULL);
8342 mono_mb_free (mb);
8343
8344 #ifdef ENABLE_ILGEN
8345 for (i = sig->param_count; i >= 0; i--)
8346 if (mspecs [i])
8347 mono_metadata_free_marshal_spec (mspecs [i]);
8348 g_free (mspecs);
8349 #endif
8350
8351 /* mono_method_print_code (res); */
8352
8353 return res;
8354 }
8355
8356 /**
8357 * mono_marshal_get_native_func_wrapper:
8358 * \param image The image to use for memory allocation and for looking up custom marshallers.
8359 * \param sig The signature of the function
8360 * \param func The native function to wrap
8361 *
8362 * \returns a wrapper method around native functions, similar to the pinvoke
8363 * wrapper.
8364 */
8365 MonoMethod *
mono_marshal_get_native_func_wrapper(MonoImage * image,MonoMethodSignature * sig,MonoMethodPInvoke * piinfo,MonoMarshalSpec ** mspecs,gpointer func)8366 mono_marshal_get_native_func_wrapper (MonoImage *image, MonoMethodSignature *sig,
8367 MonoMethodPInvoke *piinfo, MonoMarshalSpec **mspecs, gpointer func)
8368 {
8369 MonoMethodSignature *csig;
8370
8371 SignaturePointerPair key, *new_key;
8372 MonoMethodBuilder *mb;
8373 MonoMethod *res;
8374 GHashTable *cache;
8375 gboolean found;
8376 char *name;
8377
8378 key.sig = sig;
8379 key.pointer = func;
8380
8381 // Generic types are not safe to place in MonoImage caches.
8382 g_assert (!sig->is_inflated);
8383
8384 cache = get_cache (&image->native_func_wrapper_cache, signature_pointer_pair_hash, signature_pointer_pair_equal);
8385 if ((res = mono_marshal_find_in_cache (cache, &key)))
8386 return res;
8387
8388 name = g_strdup_printf ("wrapper_native_%p", func);
8389 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_MANAGED_TO_NATIVE);
8390 mb->method->save_lmf = 1;
8391
8392 #ifdef ENABLE_ILGEN
8393 mono_marshal_emit_native_wrapper (image, mb, sig, piinfo, mspecs, func, FALSE, TRUE, FALSE);
8394 #endif
8395
8396 csig = mono_metadata_signature_dup_full (image, sig);
8397 csig->pinvoke = 0;
8398
8399 new_key = g_new (SignaturePointerPair,1);
8400 new_key->sig = csig;
8401 new_key->pointer = func;
8402
8403 res = mono_mb_create_and_cache_full (cache, new_key, mb, csig, csig->param_count + 16, NULL, &found);
8404 if (found)
8405 g_free (new_key);
8406
8407 mono_mb_free (mb);
8408
8409 mono_marshal_set_wrapper_info (res, NULL);
8410
8411 return res;
8412 }
8413
8414 /*
8415 * The wrapper receives the native function as a boxed IntPtr as its 'this' argument. This is easier to support in
8416 * AOT.
8417 */
8418 MonoMethod*
mono_marshal_get_native_func_wrapper_aot(MonoClass * klass)8419 mono_marshal_get_native_func_wrapper_aot (MonoClass *klass)
8420 {
8421 MonoMethodSignature *sig, *csig;
8422 MonoMethodBuilder *mb;
8423 MonoMethod *res;
8424 GHashTable *cache;
8425 char *name;
8426 WrapperInfo *info;
8427 MonoMethodPInvoke mpiinfo;
8428 MonoMethodPInvoke *piinfo = &mpiinfo;
8429 MonoMarshalSpec **mspecs;
8430 MonoMethod *invoke = mono_get_delegate_invoke (klass);
8431 MonoImage *image = invoke->klass->image;
8432 int i;
8433
8434 // FIXME: include UnmanagedFunctionPointerAttribute info
8435
8436 /*
8437 * The wrapper is associated with the delegate type, to pick up the marshalling info etc.
8438 */
8439 cache = get_cache (&mono_method_get_wrapper_cache (invoke)->native_func_wrapper_aot_cache, mono_aligned_addr_hash, NULL);
8440
8441 if ((res = mono_marshal_find_in_cache (cache, invoke)))
8442 return res;
8443
8444 memset (&mpiinfo, 0, sizeof (mpiinfo));
8445 parse_unmanaged_function_pointer_attr (klass, &mpiinfo);
8446
8447 mspecs = g_new0 (MonoMarshalSpec*, mono_method_signature (invoke)->param_count + 1);
8448 mono_method_get_marshal_info (invoke, mspecs);
8449 /* Freed below so don't alloc from mempool */
8450 sig = mono_metadata_signature_dup (mono_method_signature (invoke));
8451 sig->hasthis = 0;
8452
8453 name = g_strdup_printf ("wrapper_aot_native");
8454 mb = mono_mb_new (invoke->klass, name, MONO_WRAPPER_MANAGED_TO_NATIVE);
8455 mb->method->save_lmf = 1;
8456
8457 #ifdef ENABLE_ILGEN
8458 mono_marshal_emit_native_wrapper (image, mb, sig, piinfo, mspecs, NULL, FALSE, TRUE, TRUE);
8459 #endif
8460
8461 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NATIVE_FUNC_AOT);
8462 info->d.managed_to_native.method = invoke;
8463
8464 g_assert (!sig->hasthis);
8465 csig = mono_metadata_signature_dup_add_this (image, sig, mono_defaults.object_class);
8466 csig->pinvoke = 0;
8467 res = mono_mb_create_and_cache_full (cache, invoke,
8468 mb, csig, csig->param_count + 16,
8469 info, NULL);
8470 mono_mb_free (mb);
8471
8472 for (i = mono_method_signature (invoke)->param_count; i >= 0; i--)
8473 if (mspecs [i])
8474 mono_metadata_free_marshal_spec (mspecs [i]);
8475 g_free (mspecs);
8476 g_free (sig);
8477
8478 return res;
8479 }
8480
8481 /*
8482 * mono_marshal_emit_managed_wrapper:
8483 *
8484 * Emit the body of a native-to-managed wrapper. INVOKE_SIG is the signature of
8485 * the delegate which wraps the managed method to be called. For closed delegates,
8486 * it could have fewer parameters than the method it wraps.
8487 * THIS_LOC is the memory location where the target of the delegate is stored.
8488 */
8489 void
mono_marshal_emit_managed_wrapper(MonoMethodBuilder * mb,MonoMethodSignature * invoke_sig,MonoMarshalSpec ** mspecs,EmitMarshalContext * m,MonoMethod * method,uint32_t target_handle)8490 mono_marshal_emit_managed_wrapper (MonoMethodBuilder *mb, MonoMethodSignature *invoke_sig, MonoMarshalSpec **mspecs, EmitMarshalContext* m, MonoMethod *method, uint32_t target_handle)
8491 {
8492 #ifndef ENABLE_ILGEN
8493 MonoMethodSignature *sig, *csig;
8494 int i;
8495
8496 sig = m->sig;
8497 csig = m->csig;
8498
8499 /* we first do all conversions */
8500 for (i = 0; i < sig->param_count; i ++) {
8501 MonoType *t = sig->params [i];
8502
8503 switch (t->type) {
8504 case MONO_TYPE_OBJECT:
8505 case MONO_TYPE_CLASS:
8506 case MONO_TYPE_VALUETYPE:
8507 case MONO_TYPE_ARRAY:
8508 case MONO_TYPE_SZARRAY:
8509 case MONO_TYPE_STRING:
8510 case MONO_TYPE_BOOLEAN:
8511 emit_marshal (m, i, sig->params [i], mspecs [i + 1], 0, &csig->params [i], MARSHAL_ACTION_MANAGED_CONV_IN);
8512 }
8513 }
8514
8515 if (!sig->ret->byref) {
8516 switch (sig->ret->type) {
8517 case MONO_TYPE_STRING:
8518 csig->ret = &mono_defaults.int_class->byval_arg;
8519 break;
8520 default:
8521 break;
8522 }
8523 }
8524 #else
8525 MonoMethodSignature *sig, *csig;
8526 MonoExceptionClause *clauses, *clause_finally, *clause_catch;
8527 int i, *tmp_locals, ex_local, e_local, attach_cookie_local, attach_dummy_local;
8528 int leave_try_pos, leave_catch_pos, ex_m1_pos;
8529 gboolean closed = FALSE;
8530
8531 sig = m->sig;
8532 csig = m->csig;
8533
8534 /* allocate local 0 (pointer) src_ptr */
8535 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
8536 /* allocate local 1 (pointer) dst_ptr */
8537 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
8538 /* allocate local 2 (boolean) delete_old */
8539 mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
8540
8541 if (!sig->hasthis && sig->param_count != invoke_sig->param_count) {
8542 /* Closed delegate */
8543 g_assert (sig->param_count == invoke_sig->param_count + 1);
8544 closed = TRUE;
8545 /* Use a new signature without the first argument */
8546 sig = mono_metadata_signature_dup (sig);
8547 memmove (&sig->params [0], &sig->params [1], (sig->param_count - 1) * sizeof (MonoType*));
8548 sig->param_count --;
8549 }
8550
8551 if (!MONO_TYPE_IS_VOID(sig->ret)) {
8552 /* allocate local 3 to store the return value */
8553 mono_mb_add_local (mb, sig->ret);
8554 }
8555
8556 if (MONO_TYPE_ISSTRUCT (sig->ret))
8557 m->vtaddr_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
8558
8559 ex_local = mono_mb_add_local (mb, &mono_defaults.uint32_class->byval_arg);
8560 e_local = mono_mb_add_local (mb, &mono_defaults.exception_class->byval_arg);
8561
8562 attach_cookie_local = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
8563 attach_dummy_local = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
8564
8565 /*
8566 * guint32 ex = -1;
8567 * try {
8568 * // does (STARTING|RUNNING|BLOCKING) -> RUNNING + set/switch domain
8569 * mono_threads_attach_coop ();
8570 *
8571 * <interrupt check>
8572 *
8573 * ret = method (...);
8574 * } catch (Exception e) {
8575 * ex = mono_gchandle_new (e, false);
8576 * } finally {
8577 * // does RUNNING -> (RUNNING|BLOCKING) + unset/switch domain
8578 * mono_threads_detach_coop ();
8579 *
8580 * if (ex != -1)
8581 * mono_marshal_ftnptr_eh_callback (ex);
8582 * }
8583 *
8584 * return ret;
8585 */
8586
8587 clauses = g_new0 (MonoExceptionClause, 2);
8588
8589 clause_catch = &clauses [0];
8590 clause_catch->flags = MONO_EXCEPTION_CLAUSE_NONE;
8591 clause_catch->data.catch_class = mono_defaults.exception_class;
8592
8593 clause_finally = &clauses [1];
8594 clause_finally->flags = MONO_EXCEPTION_CLAUSE_FINALLY;
8595
8596 mono_mb_emit_icon (mb, 0);
8597 mono_mb_emit_stloc (mb, 2);
8598
8599 mono_mb_emit_icon (mb, -1);
8600 mono_mb_emit_byte (mb, CEE_CONV_U4);
8601 mono_mb_emit_stloc (mb, ex_local);
8602
8603 /* try { */
8604 clause_catch->try_offset = clause_finally->try_offset = mono_mb_get_label (mb);
8605
8606 if (!mono_threads_is_blocking_transition_enabled ()) {
8607 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
8608 mono_mb_emit_byte (mb, CEE_MONO_JIT_ATTACH);
8609 } else {
8610 /* mono_threads_attach_coop (); */
8611 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
8612 mono_mb_emit_byte (mb, CEE_MONO_LDDOMAIN);
8613 mono_mb_emit_ldloc_addr (mb, attach_dummy_local);
8614 /*
8615 * This icall is special cased in the JIT so it works in native-to-managed wrappers in unattached threads.
8616 * Keep this in sync with the CEE_JIT_ICALL code in the JIT.
8617 */
8618 mono_mb_emit_icall (mb, mono_threads_attach_coop);
8619 mono_mb_emit_stloc (mb, attach_cookie_local);
8620 }
8621
8622 /* <interrupt check> */
8623 emit_thread_interrupt_checkpoint (mb);
8624
8625 /* we first do all conversions */
8626 tmp_locals = (int *)alloca (sizeof (int) * sig->param_count);
8627 for (i = 0; i < sig->param_count; i ++) {
8628 MonoType *t = sig->params [i];
8629
8630 switch (t->type) {
8631 case MONO_TYPE_OBJECT:
8632 case MONO_TYPE_CLASS:
8633 case MONO_TYPE_VALUETYPE:
8634 case MONO_TYPE_ARRAY:
8635 case MONO_TYPE_SZARRAY:
8636 case MONO_TYPE_STRING:
8637 case MONO_TYPE_BOOLEAN:
8638 tmp_locals [i] = emit_marshal (m, i, sig->params [i], mspecs [i + 1], 0, &csig->params [i], MARSHAL_ACTION_MANAGED_CONV_IN);
8639
8640 break;
8641 default:
8642 tmp_locals [i] = 0;
8643 break;
8644 }
8645 }
8646
8647 if (sig->hasthis) {
8648 if (target_handle) {
8649 mono_mb_emit_icon (mb, (gint32)target_handle);
8650 mono_mb_emit_icall (mb, mono_gchandle_get_target);
8651 } else {
8652 /* fixme: */
8653 g_assert_not_reached ();
8654 }
8655 } else if (closed) {
8656 mono_mb_emit_icon (mb, (gint32)target_handle);
8657 mono_mb_emit_icall (mb, mono_gchandle_get_target);
8658 }
8659
8660 for (i = 0; i < sig->param_count; i++) {
8661 MonoType *t = sig->params [i];
8662
8663 if (tmp_locals [i]) {
8664 if (t->byref)
8665 mono_mb_emit_ldloc_addr (mb, tmp_locals [i]);
8666 else
8667 mono_mb_emit_ldloc (mb, tmp_locals [i]);
8668 }
8669 else
8670 mono_mb_emit_ldarg (mb, i);
8671 }
8672
8673 /* ret = method (...) */
8674 mono_mb_emit_managed_call (mb, method, NULL);
8675
8676 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
8677 MonoClass *klass = mono_class_from_mono_type (sig->ret);
8678 mono_class_init (klass);
8679 if (!(mono_class_is_explicit_layout (klass) || klass->blittable)) {
8680 /* This is used by emit_marshal_vtype (), but it needs to go right before the call */
8681 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
8682 mono_mb_emit_byte (mb, CEE_MONO_VTADDR);
8683 mono_mb_emit_stloc (mb, m->vtaddr_var);
8684 }
8685 }
8686
8687 if (mspecs [0] && mspecs [0]->native == MONO_NATIVE_CUSTOM) {
8688 emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
8689 } else if (!sig->ret->byref) {
8690 switch (sig->ret->type) {
8691 case MONO_TYPE_VOID:
8692 break;
8693 case MONO_TYPE_BOOLEAN:
8694 case MONO_TYPE_I1:
8695 case MONO_TYPE_U1:
8696 case MONO_TYPE_CHAR:
8697 case MONO_TYPE_I2:
8698 case MONO_TYPE_U2:
8699 case MONO_TYPE_I4:
8700 case MONO_TYPE_U4:
8701 case MONO_TYPE_I:
8702 case MONO_TYPE_U:
8703 case MONO_TYPE_PTR:
8704 case MONO_TYPE_R4:
8705 case MONO_TYPE_R8:
8706 case MONO_TYPE_I8:
8707 case MONO_TYPE_U8:
8708 case MONO_TYPE_OBJECT:
8709 mono_mb_emit_stloc (mb, 3);
8710 break;
8711 case MONO_TYPE_STRING:
8712 csig->ret = &mono_defaults.int_class->byval_arg;
8713 emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
8714 break;
8715 case MONO_TYPE_VALUETYPE:
8716 case MONO_TYPE_CLASS:
8717 case MONO_TYPE_SZARRAY:
8718 emit_marshal (m, 0, sig->ret, mspecs [0], 0, NULL, MARSHAL_ACTION_MANAGED_CONV_RESULT);
8719 break;
8720 default:
8721 g_warning ("return type 0x%02x unknown", sig->ret->type);
8722 g_assert_not_reached ();
8723 }
8724 } else {
8725 mono_mb_emit_stloc (mb, 3);
8726 }
8727
8728 /* Convert byref arguments back */
8729 for (i = 0; i < sig->param_count; i ++) {
8730 MonoType *t = sig->params [i];
8731 MonoMarshalSpec *spec = mspecs [i + 1];
8732
8733 if (spec && spec->native == MONO_NATIVE_CUSTOM) {
8734 emit_marshal (m, i, t, mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT);
8735 }
8736 else if (t->byref) {
8737 switch (t->type) {
8738 case MONO_TYPE_CLASS:
8739 case MONO_TYPE_VALUETYPE:
8740 case MONO_TYPE_OBJECT:
8741 case MONO_TYPE_STRING:
8742 case MONO_TYPE_BOOLEAN:
8743 emit_marshal (m, i, t, mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT);
8744 break;
8745 default:
8746 break;
8747 }
8748 }
8749 else if (invoke_sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT) {
8750 /* The [Out] information is encoded in the delegate signature */
8751 switch (t->type) {
8752 case MONO_TYPE_SZARRAY:
8753 case MONO_TYPE_CLASS:
8754 case MONO_TYPE_VALUETYPE:
8755 emit_marshal (m, i, invoke_sig->params [i], mspecs [i + 1], tmp_locals [i], NULL, MARSHAL_ACTION_MANAGED_CONV_OUT);
8756 break;
8757 default:
8758 g_assert_not_reached ();
8759 }
8760 }
8761 }
8762
8763 leave_try_pos = mono_mb_emit_branch (mb, CEE_LEAVE);
8764
8765 /* } [endtry] */
8766
8767 /* catch (Exception e) { */
8768 clause_catch->try_len = mono_mb_get_label (mb) - clause_catch->try_offset;
8769 clause_catch->handler_offset = mono_mb_get_label (mb);
8770
8771 mono_mb_emit_stloc (mb, e_local);
8772
8773 /* ex = mono_gchandle_new (e, false); */
8774 mono_mb_emit_ldloc (mb, e_local);
8775 mono_mb_emit_icon (mb, 0);
8776 mono_mb_emit_icall (mb, mono_gchandle_new);
8777 mono_mb_emit_stloc (mb, ex_local);
8778
8779 leave_catch_pos = mono_mb_emit_branch (mb, CEE_LEAVE);
8780
8781 /* } [endcatch] */
8782 clause_catch->handler_len = mono_mb_get_pos (mb) - clause_catch->handler_offset;
8783
8784 /* finally { */
8785 clause_finally->try_len = mono_mb_get_label (mb) - clause_finally->try_offset;
8786 clause_finally->handler_offset = mono_mb_get_label (mb);
8787
8788 if (!mono_threads_is_blocking_transition_enabled ()) {
8789 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
8790 mono_mb_emit_byte (mb, CEE_MONO_JIT_DETACH);
8791 } else {
8792 /* mono_threads_detach_coop (); */
8793 mono_mb_emit_ldloc (mb, attach_cookie_local);
8794 mono_mb_emit_ldloc_addr (mb, attach_dummy_local);
8795 mono_mb_emit_icall (mb, mono_threads_detach_coop);
8796 }
8797
8798 /* if (ex != -1) */
8799 mono_mb_emit_ldloc (mb, ex_local);
8800 mono_mb_emit_icon (mb, -1);
8801 mono_mb_emit_byte (mb, CEE_CONV_U4);
8802 ex_m1_pos = mono_mb_emit_branch (mb, CEE_BEQ);
8803
8804 /* mono_marshal_ftnptr_eh_callback (ex) */
8805 mono_mb_emit_ldloc (mb, ex_local);
8806 mono_mb_emit_icall (mb, mono_marshal_ftnptr_eh_callback);
8807
8808 /* [ex == -1] */
8809 mono_mb_patch_branch (mb, ex_m1_pos);
8810
8811 mono_mb_emit_byte (mb, CEE_ENDFINALLY);
8812
8813 /* } [endfinally] */
8814 clause_finally->handler_len = mono_mb_get_pos (mb) - clause_finally->handler_offset;
8815
8816 mono_mb_patch_branch (mb, leave_try_pos);
8817 mono_mb_patch_branch (mb, leave_catch_pos);
8818
8819 /* return ret; */
8820 if (m->retobj_var) {
8821 mono_mb_emit_ldloc (mb, m->retobj_var);
8822 mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
8823 mono_mb_emit_op (mb, CEE_MONO_RETOBJ, m->retobj_class);
8824 }
8825 else {
8826 if (!MONO_TYPE_IS_VOID(sig->ret))
8827 mono_mb_emit_ldloc (mb, 3);
8828 mono_mb_emit_byte (mb, CEE_RET);
8829 }
8830
8831 mono_mb_set_clauses (mb, 2, clauses);
8832
8833 if (closed)
8834 g_free (sig);
8835 #endif
8836 }
8837
8838 static void
mono_marshal_set_callconv_from_modopt(MonoMethod * method,MonoMethodSignature * csig)8839 mono_marshal_set_callconv_from_modopt (MonoMethod *method, MonoMethodSignature *csig)
8840 {
8841 MonoMethodSignature *sig;
8842 int i;
8843
8844 #ifdef TARGET_WIN32
8845 /*
8846 * Under windows, delegates passed to native code must use the STDCALL
8847 * calling convention.
8848 */
8849 csig->call_convention = MONO_CALL_STDCALL;
8850 #endif
8851
8852 sig = mono_method_signature (method);
8853
8854 /* Change default calling convention if needed */
8855 /* Why is this a modopt ? */
8856 if (sig->ret && sig->ret->num_mods) {
8857 for (i = 0; i < sig->ret->num_mods; ++i) {
8858 MonoError error;
8859 MonoClass *cmod_class = mono_class_get_checked (method->klass->image, sig->ret->modifiers [i].token, &error);
8860 g_assert (mono_error_ok (&error));
8861 if ((cmod_class->image == mono_defaults.corlib) && !strcmp (cmod_class->name_space, "System.Runtime.CompilerServices")) {
8862 if (!strcmp (cmod_class->name, "CallConvCdecl"))
8863 csig->call_convention = MONO_CALL_C;
8864 else if (!strcmp (cmod_class->name, "CallConvStdcall"))
8865 csig->call_convention = MONO_CALL_STDCALL;
8866 else if (!strcmp (cmod_class->name, "CallConvFastcall"))
8867 csig->call_convention = MONO_CALL_FASTCALL;
8868 else if (!strcmp (cmod_class->name, "CallConvThiscall"))
8869 csig->call_convention = MONO_CALL_THISCALL;
8870 }
8871 }
8872 }
8873 }
8874
8875 /**
8876 * mono_marshal_get_managed_wrapper:
8877 * Generates IL code to call managed methods from unmanaged code
8878 * If \p target_handle is \c 0, the wrapper info will be a \c WrapperInfo structure.
8879 */
8880 MonoMethod *
mono_marshal_get_managed_wrapper(MonoMethod * method,MonoClass * delegate_klass,uint32_t target_handle,MonoError * error)8881 mono_marshal_get_managed_wrapper (MonoMethod *method, MonoClass *delegate_klass, uint32_t target_handle, MonoError *error)
8882 {
8883 MonoMethodSignature *sig, *csig, *invoke_sig;
8884 MonoMethodBuilder *mb;
8885 MonoMethod *res, *invoke;
8886 MonoMarshalSpec **mspecs;
8887 MonoMethodPInvoke piinfo;
8888 GHashTable *cache;
8889 int i;
8890 EmitMarshalContext m;
8891
8892 g_assert (method != NULL);
8893 error_init (error);
8894
8895 if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
8896 mono_error_set_invalid_program (error, "Failed because method (%s) marked PInvokeCallback (managed method) and extern (unmanaged) simultaneously.", mono_method_full_name (method, TRUE));
8897 return NULL;
8898 }
8899
8900 /*
8901 * FIXME: Should cache the method+delegate type pair, since the same method
8902 * could be called with different delegates, thus different marshalling
8903 * options.
8904 */
8905 cache = get_cache (&mono_method_get_wrapper_cache (method)->managed_wrapper_cache, mono_aligned_addr_hash, NULL);
8906
8907 if (!target_handle && (res = mono_marshal_find_in_cache (cache, method)))
8908 return res;
8909
8910 invoke = mono_get_delegate_invoke (delegate_klass);
8911 invoke_sig = mono_method_signature (invoke);
8912
8913 mspecs = g_new0 (MonoMarshalSpec*, mono_method_signature (invoke)->param_count + 1);
8914 mono_method_get_marshal_info (invoke, mspecs);
8915
8916 sig = mono_method_signature (method);
8917
8918 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
8919
8920 /*the target gchandle must be the first entry after size and the wrapper itself.*/
8921 mono_mb_add_data (mb, GUINT_TO_POINTER (target_handle));
8922
8923 /* we copy the signature, so that we can modify it */
8924 if (target_handle)
8925 /* Need to free this later */
8926 csig = mono_metadata_signature_dup (invoke_sig);
8927 else
8928 csig = mono_metadata_signature_dup_full (method->klass->image, invoke_sig);
8929 csig->hasthis = 0;
8930 csig->pinvoke = 1;
8931
8932 memset (&m, 0, sizeof (m));
8933 m.mb = mb;
8934 m.sig = sig;
8935 m.piinfo = NULL;
8936 m.retobj_var = 0;
8937 m.csig = csig;
8938 m.image = method->klass->image;
8939
8940 mono_marshal_set_callconv_from_modopt (invoke, csig);
8941
8942 /* The attribute is only available in Net 2.0 */
8943 if (mono_class_try_get_unmanaged_function_pointer_attribute_class ()) {
8944 MonoCustomAttrInfo *cinfo;
8945 MonoCustomAttrEntry *attr;
8946
8947 /*
8948 * The pinvoke attributes are stored in a real custom attribute. Obtain the
8949 * contents of the attribute without constructing it, as that might not be
8950 * possible when running in cross-compiling mode.
8951 */
8952 cinfo = mono_custom_attrs_from_class_checked (delegate_klass, error);
8953 mono_error_assert_ok (error);
8954 attr = NULL;
8955 if (cinfo) {
8956 for (i = 0; i < cinfo->num_attrs; ++i) {
8957 MonoClass *ctor_class = cinfo->attrs [i].ctor->klass;
8958 if (mono_class_has_parent (ctor_class, mono_class_try_get_unmanaged_function_pointer_attribute_class ())) {
8959 attr = &cinfo->attrs [i];
8960 break;
8961 }
8962 }
8963 }
8964 if (attr) {
8965 MonoArray *typed_args, *named_args;
8966 CattrNamedArg *arginfo;
8967 MonoObject *o;
8968 gint32 call_conv;
8969 gint32 charset = 0;
8970 MonoBoolean set_last_error = 0;
8971 MonoError error;
8972
8973 mono_reflection_create_custom_attr_data_args (mono_defaults.corlib, attr->ctor, attr->data, attr->data_size, &typed_args, &named_args, &arginfo, &error);
8974 g_assert (mono_error_ok (&error));
8975 g_assert (mono_array_length (typed_args) == 1);
8976
8977 /* typed args */
8978 o = mono_array_get (typed_args, MonoObject*, 0);
8979 call_conv = *(gint32*)mono_object_unbox (o);
8980
8981 /* named args */
8982 for (i = 0; i < mono_array_length (named_args); ++i) {
8983 CattrNamedArg *narg = &arginfo [i];
8984
8985 o = mono_array_get (named_args, MonoObject*, i);
8986
8987 g_assert (narg->field);
8988 if (!strcmp (narg->field->name, "CharSet")) {
8989 charset = *(gint32*)mono_object_unbox (o);
8990 } else if (!strcmp (narg->field->name, "SetLastError")) {
8991 set_last_error = *(MonoBoolean*)mono_object_unbox (o);
8992 } else if (!strcmp (narg->field->name, "BestFitMapping")) {
8993 // best_fit_mapping = *(MonoBoolean*)mono_object_unbox (o);
8994 } else if (!strcmp (narg->field->name, "ThrowOnUnmappableChar")) {
8995 // throw_on_unmappable = *(MonoBoolean*)mono_object_unbox (o);
8996 } else {
8997 g_assert_not_reached ();
8998 }
8999 }
9000
9001 g_free (arginfo);
9002
9003 memset (&piinfo, 0, sizeof (piinfo));
9004 m.piinfo = &piinfo;
9005 piinfo.piflags = (call_conv << 8) | (charset ? (charset - 1) * 2 : 1) | set_last_error;
9006
9007 csig->call_convention = call_conv - 1;
9008 }
9009
9010 if (cinfo && !cinfo->cached)
9011 mono_custom_attrs_free (cinfo);
9012 }
9013
9014 mono_marshal_emit_managed_wrapper (mb, invoke_sig, mspecs, &m, method, target_handle);
9015
9016 if (!target_handle) {
9017 WrapperInfo *info;
9018
9019 // FIXME: Associate it with the method+delegate_klass pair
9020 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NONE);
9021 info->d.native_to_managed.method = method;
9022 info->d.native_to_managed.klass = delegate_klass;
9023
9024 res = mono_mb_create_and_cache_full (cache, method,
9025 mb, csig, sig->param_count + 16,
9026 info, NULL);
9027 } else {
9028 #ifdef ENABLE_ILGEN
9029 mb->dynamic = TRUE;
9030 #endif
9031 res = mono_mb_create (mb, csig, sig->param_count + 16, NULL);
9032 }
9033 mono_mb_free (mb);
9034
9035 for (i = mono_method_signature (invoke)->param_count; i >= 0; i--)
9036 if (mspecs [i])
9037 mono_metadata_free_marshal_spec (mspecs [i]);
9038 g_free (mspecs);
9039
9040 /* mono_method_print_code (res); */
9041
9042 return res;
9043 }
9044
9045 gpointer
mono_marshal_get_vtfixup_ftnptr(MonoImage * image,guint32 token,guint16 type)9046 mono_marshal_get_vtfixup_ftnptr (MonoImage *image, guint32 token, guint16 type)
9047 {
9048 MonoError error;
9049 MonoMethod *method;
9050 MonoMethodSignature *sig;
9051 MonoMethodBuilder *mb;
9052 int i, param_count;
9053
9054 g_assert (token);
9055
9056 method = mono_get_method_checked (image, token, NULL, NULL, &error);
9057 if (!method)
9058 g_error ("Could not load vtfixup token 0x%x due to %s", token, mono_error_get_message (&error));
9059 g_assert (method);
9060
9061 if (type & (VTFIXUP_TYPE_FROM_UNMANAGED | VTFIXUP_TYPE_FROM_UNMANAGED_RETAIN_APPDOMAIN)) {
9062 MonoMethodSignature *csig;
9063 MonoMarshalSpec **mspecs;
9064 EmitMarshalContext m;
9065
9066 sig = mono_method_signature (method);
9067 g_assert (!sig->hasthis);
9068
9069 mspecs = g_new0 (MonoMarshalSpec*, sig->param_count + 1);
9070 mono_method_get_marshal_info (method, mspecs);
9071
9072 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
9073 csig = mono_metadata_signature_dup_full (image, sig);
9074 csig->hasthis = 0;
9075 csig->pinvoke = 1;
9076
9077 memset (&m, 0, sizeof (m));
9078 m.mb = mb;
9079 m.sig = sig;
9080 m.piinfo = NULL;
9081 m.retobj_var = 0;
9082 m.csig = csig;
9083 m.image = image;
9084
9085 mono_marshal_set_callconv_from_modopt (method, csig);
9086
9087 /* FIXME: Implement VTFIXUP_TYPE_FROM_UNMANAGED_RETAIN_APPDOMAIN. */
9088
9089 mono_marshal_emit_managed_wrapper (mb, sig, mspecs, &m, method, 0);
9090
9091 #ifdef ENABLE_ILGEN
9092 mb->dynamic = TRUE;
9093 #endif
9094 method = mono_mb_create (mb, csig, sig->param_count + 16, NULL);
9095 mono_mb_free (mb);
9096
9097 for (i = sig->param_count; i >= 0; i--)
9098 if (mspecs [i])
9099 mono_metadata_free_marshal_spec (mspecs [i]);
9100 g_free (mspecs);
9101
9102 gpointer compiled_ptr = mono_compile_method_checked (method, &error);
9103 mono_error_assert_ok (&error);
9104 return compiled_ptr;
9105 }
9106
9107 sig = mono_method_signature (method);
9108 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_MANAGED_TO_MANAGED);
9109
9110 param_count = sig->param_count + sig->hasthis;
9111 #ifdef ENABLE_ILGEN
9112 for (i = 0; i < param_count; i++)
9113 mono_mb_emit_ldarg (mb, i);
9114
9115 if (type & VTFIXUP_TYPE_CALL_MOST_DERIVED)
9116 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
9117 else
9118 mono_mb_emit_op (mb, CEE_CALL, method);
9119 mono_mb_emit_byte (mb, CEE_RET);
9120
9121 mb->dynamic = TRUE;
9122 #endif
9123
9124 method = mono_mb_create (mb, sig, param_count, NULL);
9125 mono_mb_free (mb);
9126
9127 gpointer compiled_ptr = mono_compile_method_checked (method, &error);
9128 mono_error_assert_ok (&error);
9129 return compiled_ptr;
9130 }
9131
9132 #ifdef ENABLE_ILGEN
9133
9134 /*
9135 * The code directly following this is the cache hit, value positive branch
9136 *
9137 * This function takes a new method builder with 0 locals and adds two locals
9138 * to create multiple out-branches and the fall through state of having the object
9139 * on the stack after a cache miss
9140 */
9141 static void
generate_check_cache(int obj_arg_position,int class_arg_position,int cache_arg_position,int * null_obj,int * cache_hit_neg,int * cache_hit_pos,MonoMethodBuilder * mb)9142 generate_check_cache (int obj_arg_position, int class_arg_position, int cache_arg_position, // In-parameters
9143 int *null_obj, int *cache_hit_neg, int *cache_hit_pos, // Out-parameters
9144 MonoMethodBuilder *mb)
9145 {
9146 int cache_miss_pos;
9147
9148 /* allocate local 0 (pointer) obj_vtable */
9149 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
9150 /* allocate local 1 (pointer) cached_vtable */
9151 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
9152
9153 /*if (!obj)*/
9154 mono_mb_emit_ldarg (mb, obj_arg_position);
9155 *null_obj = mono_mb_emit_branch (mb, CEE_BRFALSE);
9156
9157 /*obj_vtable = obj->vtable;*/
9158 mono_mb_emit_ldarg (mb, obj_arg_position);
9159 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoObject, vtable));
9160 mono_mb_emit_byte (mb, CEE_LDIND_I);
9161 mono_mb_emit_stloc (mb, 0);
9162
9163 /* cached_vtable = *cache*/
9164 mono_mb_emit_ldarg (mb, cache_arg_position);
9165 mono_mb_emit_byte (mb, CEE_LDIND_I);
9166 mono_mb_emit_stloc (mb, 1);
9167
9168 mono_mb_emit_ldloc (mb, 1);
9169 mono_mb_emit_byte (mb, CEE_LDC_I4);
9170 mono_mb_emit_i4 (mb, ~0x1);
9171 mono_mb_emit_byte (mb, CEE_CONV_I);
9172 mono_mb_emit_byte (mb, CEE_AND);
9173 mono_mb_emit_ldloc (mb, 0);
9174 /*if ((cached_vtable & ~0x1)== obj_vtable)*/
9175 cache_miss_pos = mono_mb_emit_branch (mb, CEE_BNE_UN);
9176
9177 /*return (cached_vtable & 0x1) ? NULL : obj;*/
9178 mono_mb_emit_ldloc (mb, 1);
9179 mono_mb_emit_byte(mb, CEE_LDC_I4_1);
9180 mono_mb_emit_byte (mb, CEE_CONV_U);
9181 mono_mb_emit_byte (mb, CEE_AND);
9182 *cache_hit_neg = mono_mb_emit_branch (mb, CEE_BRTRUE);
9183 *cache_hit_pos = mono_mb_emit_branch (mb, CEE_BR);
9184
9185 // slow path
9186 mono_mb_patch_branch (mb, cache_miss_pos);
9187
9188 // if isinst
9189 mono_mb_emit_ldarg (mb, obj_arg_position);
9190 mono_mb_emit_ldarg (mb, class_arg_position);
9191 mono_mb_emit_ldarg (mb, cache_arg_position);
9192 mono_mb_emit_icall (mb, mono_marshal_isinst_with_cache);
9193 }
9194
9195 #endif /* ENABLE_ILGEN */
9196
9197 /**
9198 * mono_marshal_get_castclass_with_cache:
9199 * This does the equivalent of \c mono_object_castclass_with_cache.
9200 */
9201 MonoMethod *
mono_marshal_get_castclass_with_cache(void)9202 mono_marshal_get_castclass_with_cache (void)
9203 {
9204 static MonoMethod *cached;
9205 MonoMethod *res;
9206 MonoMethodBuilder *mb;
9207 MonoMethodSignature *sig;
9208 int return_null_pos, positive_cache_hit_pos, negative_cache_hit_pos, invalid_cast_pos;
9209 WrapperInfo *info;
9210
9211 const int obj_arg_position = 0;
9212 const int class_arg_position = 1;
9213 const int cache_arg_position = 2;
9214
9215 if (cached)
9216 return cached;
9217
9218 mb = mono_mb_new (mono_defaults.object_class, "__castclass_with_cache", MONO_WRAPPER_CASTCLASS);
9219 sig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
9220 sig->params [obj_arg_position] = &mono_defaults.object_class->byval_arg;
9221 sig->params [class_arg_position] = &mono_defaults.int_class->byval_arg;
9222 sig->params [cache_arg_position] = &mono_defaults.int_class->byval_arg;
9223 sig->ret = &mono_defaults.object_class->byval_arg;
9224 sig->pinvoke = 0;
9225
9226 #ifdef ENABLE_ILGEN
9227 generate_check_cache (obj_arg_position, class_arg_position, cache_arg_position,
9228 &return_null_pos, &negative_cache_hit_pos, &positive_cache_hit_pos, mb);
9229 invalid_cast_pos = mono_mb_emit_branch (mb, CEE_BRFALSE);
9230
9231 /*return obj;*/
9232 mono_mb_patch_branch (mb, positive_cache_hit_pos);
9233 mono_mb_emit_ldarg (mb, obj_arg_position);
9234 mono_mb_emit_byte (mb, CEE_RET);
9235
9236 /*fails*/
9237 mono_mb_patch_branch (mb, negative_cache_hit_pos);
9238 mono_mb_patch_branch (mb, invalid_cast_pos);
9239 mono_mb_emit_exception (mb, "InvalidCastException", NULL);
9240
9241 /*return null*/
9242 mono_mb_patch_branch (mb, return_null_pos);
9243 mono_mb_emit_byte (mb, CEE_LDNULL);
9244 mono_mb_emit_byte (mb, CEE_RET);
9245 #endif /* ENABLE_ILGEN */
9246
9247 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_CASTCLASS_WITH_CACHE);
9248 res = mono_mb_create (mb, sig, 8, info);
9249 STORE_STORE_FENCE;
9250
9251 if (mono_atomic_cas_ptr ((volatile gpointer *)&cached, res, NULL)) {
9252 mono_free_method (res);
9253 mono_metadata_free_method_signature (sig);
9254 }
9255 mono_mb_free (mb);
9256
9257 return cached;
9258 }
9259
9260 /* this is an icall */
9261 static MonoObject *
mono_marshal_isinst_with_cache(MonoObject * obj,MonoClass * klass,uintptr_t * cache)9262 mono_marshal_isinst_with_cache (MonoObject *obj, MonoClass *klass, uintptr_t *cache)
9263 {
9264 MonoError error;
9265 MonoObject *isinst = mono_object_isinst_checked (obj, klass, &error);
9266 if (mono_error_set_pending_exception (&error))
9267 return NULL;
9268
9269 if (mono_object_is_transparent_proxy (obj))
9270 return isinst;
9271
9272 uintptr_t cache_update = (uintptr_t)obj->vtable;
9273 if (!isinst)
9274 cache_update = cache_update | 0x1;
9275
9276 *cache = cache_update;
9277
9278 return isinst;
9279 }
9280
9281 /**
9282 * mono_marshal_get_isinst_with_cache:
9283 * This does the equivalent of \c mono_marshal_isinst_with_cache.
9284 */
9285 MonoMethod *
mono_marshal_get_isinst_with_cache(void)9286 mono_marshal_get_isinst_with_cache (void)
9287 {
9288 static MonoMethod *cached;
9289 MonoMethod *res;
9290 MonoMethodBuilder *mb;
9291 MonoMethodSignature *sig;
9292 int return_null_pos, positive_cache_hit_pos, negative_cache_hit_pos;
9293 WrapperInfo *info;
9294
9295 const int obj_arg_position = 0;
9296 const int class_arg_position = 1;
9297 const int cache_arg_position = 2;
9298
9299 if (cached)
9300 return cached;
9301
9302 mb = mono_mb_new (mono_defaults.object_class, "__isinst_with_cache", MONO_WRAPPER_CASTCLASS);
9303 sig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
9304 // The object
9305 sig->params [obj_arg_position] = &mono_defaults.object_class->byval_arg;
9306 // The class
9307 sig->params [class_arg_position] = &mono_defaults.int_class->byval_arg;
9308 // The cache
9309 sig->params [cache_arg_position] = &mono_defaults.int_class->byval_arg;
9310 sig->ret = &mono_defaults.object_class->byval_arg;
9311 sig->pinvoke = 0;
9312
9313 #ifdef ENABLE_ILGEN
9314 generate_check_cache (obj_arg_position, class_arg_position, cache_arg_position,
9315 &return_null_pos, &negative_cache_hit_pos, &positive_cache_hit_pos, mb);
9316 // Return the object gotten via the slow path.
9317 mono_mb_emit_byte (mb, CEE_RET);
9318
9319 // return NULL;
9320 mono_mb_patch_branch (mb, negative_cache_hit_pos);
9321 mono_mb_patch_branch (mb, return_null_pos);
9322 mono_mb_emit_byte (mb, CEE_LDNULL);
9323 mono_mb_emit_byte (mb, CEE_RET);
9324
9325 // return obj
9326 mono_mb_patch_branch (mb, positive_cache_hit_pos);
9327 mono_mb_emit_ldarg (mb, obj_arg_position);
9328 mono_mb_emit_byte (mb, CEE_RET);
9329 #endif
9330
9331 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_ISINST_WITH_CACHE);
9332 res = mono_mb_create (mb, sig, 8, info);
9333 STORE_STORE_FENCE;
9334
9335 if (mono_atomic_cas_ptr ((volatile gpointer *)&cached, res, NULL)) {
9336 mono_free_method (res);
9337 mono_metadata_free_method_signature (sig);
9338 }
9339 mono_mb_free (mb);
9340
9341 return cached;
9342 }
9343
9344 /**
9345 * mono_marshal_get_struct_to_ptr:
9346 * \param klass \c MonoClass
9347 *
9348 * Generates IL code for <code>StructureToPtr (object structure, IntPtr ptr, bool fDeleteOld)</code>
9349 */
9350 MonoMethod *
mono_marshal_get_struct_to_ptr(MonoClass * klass)9351 mono_marshal_get_struct_to_ptr (MonoClass *klass)
9352 {
9353 MonoMethodBuilder *mb;
9354 static MonoMethod *stoptr = NULL;
9355 MonoMethod *res;
9356 WrapperInfo *info;
9357
9358 g_assert (klass != NULL);
9359
9360 mono_marshal_load_type_info (klass);
9361
9362 MonoMarshalType *marshal_info = mono_class_get_marshal_info (klass);
9363 if (marshal_info->str_to_ptr)
9364 return marshal_info->str_to_ptr;
9365
9366 if (!stoptr)
9367 stoptr = mono_class_get_method_from_name (mono_defaults.marshal_class, "StructureToPtr", 3);
9368 g_assert (stoptr);
9369
9370 mb = mono_mb_new (klass, stoptr->name, MONO_WRAPPER_UNKNOWN);
9371
9372 #ifdef ENABLE_ILGEN
9373 if (klass->blittable) {
9374 mono_mb_emit_byte (mb, CEE_LDARG_1);
9375 mono_mb_emit_byte (mb, CEE_LDARG_0);
9376 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
9377 mono_mb_emit_icon (mb, mono_class_value_size (klass, NULL));
9378 mono_mb_emit_byte (mb, CEE_PREFIX1);
9379 mono_mb_emit_byte (mb, CEE_CPBLK);
9380 } else {
9381
9382 /* allocate local 0 (pointer) src_ptr */
9383 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
9384 /* allocate local 1 (pointer) dst_ptr */
9385 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
9386 /* allocate local 2 (boolean) delete_old */
9387 mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
9388 mono_mb_emit_byte (mb, CEE_LDARG_2);
9389 mono_mb_emit_stloc (mb, 2);
9390
9391 /* initialize src_ptr to point to the start of object data */
9392 mono_mb_emit_byte (mb, CEE_LDARG_0);
9393 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
9394 mono_mb_emit_stloc (mb, 0);
9395
9396 /* initialize dst_ptr */
9397 mono_mb_emit_byte (mb, CEE_LDARG_1);
9398 mono_mb_emit_stloc (mb, 1);
9399
9400 emit_struct_conv (mb, klass, FALSE);
9401 }
9402
9403 mono_mb_emit_byte (mb, CEE_RET);
9404 #endif
9405 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_STRUCTURE_TO_PTR);
9406 res = mono_mb_create (mb, mono_signature_no_pinvoke (stoptr), 0, info);
9407 mono_mb_free (mb);
9408
9409 mono_marshal_lock ();
9410 if (!marshal_info->str_to_ptr)
9411 marshal_info->str_to_ptr = res;
9412 else
9413 res = marshal_info->str_to_ptr;
9414 mono_marshal_unlock ();
9415 return res;
9416 }
9417
9418 /**
9419 * mono_marshal_get_ptr_to_struct:
9420 * \param klass \c MonoClass
9421 * Generates IL code for <code>PtrToStructure (IntPtr src, object structure)</code>
9422 */
9423 MonoMethod *
mono_marshal_get_ptr_to_struct(MonoClass * klass)9424 mono_marshal_get_ptr_to_struct (MonoClass *klass)
9425 {
9426 MonoMethodBuilder *mb;
9427 static MonoMethodSignature *ptostr = NULL;
9428 MonoMethod *res;
9429 WrapperInfo *info;
9430
9431 g_assert (klass != NULL);
9432
9433 mono_marshal_load_type_info (klass);
9434
9435 MonoMarshalType *marshal_info = mono_class_get_marshal_info (klass);
9436 if (marshal_info->ptr_to_str)
9437 return marshal_info->ptr_to_str;
9438
9439 if (!ptostr) {
9440 MonoMethodSignature *sig;
9441
9442 /* Create the signature corresponding to
9443 static void PtrToStructure (IntPtr ptr, object structure);
9444 defined in class/corlib/System.Runtime.InteropServices/Marshal.cs */
9445 sig = mono_create_icall_signature ("void ptr object");
9446 sig = mono_metadata_signature_dup_full (mono_defaults.corlib, sig);
9447 sig->pinvoke = 0;
9448 mono_memory_barrier ();
9449 ptostr = sig;
9450 }
9451
9452 mb = mono_mb_new (klass, "PtrToStructure", MONO_WRAPPER_UNKNOWN);
9453
9454 #ifdef ENABLE_ILGEN
9455 if (klass->blittable) {
9456 mono_mb_emit_byte (mb, CEE_LDARG_1);
9457 mono_mb_emit_ldflda (mb, sizeof (MonoObject));
9458 mono_mb_emit_byte (mb, CEE_LDARG_0);
9459 mono_mb_emit_icon (mb, mono_class_value_size (klass, NULL));
9460 mono_mb_emit_byte (mb, CEE_PREFIX1);
9461 mono_mb_emit_byte (mb, CEE_CPBLK);
9462 } else {
9463
9464 /* allocate local 0 (pointer) src_ptr */
9465 mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
9466 /* allocate local 1 (pointer) dst_ptr */
9467 mono_mb_add_local (mb, &klass->this_arg);
9468
9469 /* initialize src_ptr to point to the start of object data */
9470 mono_mb_emit_byte (mb, CEE_LDARG_0);
9471 mono_mb_emit_stloc (mb, 0);
9472
9473 /* initialize dst_ptr */
9474 mono_mb_emit_byte (mb, CEE_LDARG_1);
9475 mono_mb_emit_op (mb, CEE_UNBOX, klass);
9476 mono_mb_emit_stloc (mb, 1);
9477
9478 emit_struct_conv (mb, klass, TRUE);
9479 }
9480
9481 mono_mb_emit_byte (mb, CEE_RET);
9482 #endif
9483 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_PTR_TO_STRUCTURE);
9484 res = mono_mb_create (mb, ptostr, 0, info);
9485 mono_mb_free (mb);
9486
9487 mono_marshal_lock ();
9488 if (!marshal_info->ptr_to_str)
9489 marshal_info->ptr_to_str = res;
9490 else
9491 res = marshal_info->ptr_to_str;
9492 mono_marshal_unlock ();
9493 return res;
9494 }
9495
9496 /*
9497 * Return a dummy wrapper for METHOD which is called by synchronized wrappers.
9498 * This is used to avoid infinite recursion since it is hard to determine where to
9499 * replace a method with its synchronized wrapper, and where not.
9500 * The runtime should execute METHOD instead of the wrapper.
9501 */
9502 MonoMethod *
mono_marshal_get_synchronized_inner_wrapper(MonoMethod * method)9503 mono_marshal_get_synchronized_inner_wrapper (MonoMethod *method)
9504 {
9505 MonoMethodBuilder *mb;
9506 WrapperInfo *info;
9507 MonoMethodSignature *sig;
9508 MonoMethod *res;
9509 MonoGenericContext *ctx = NULL;
9510 MonoGenericContainer *container = NULL;
9511
9512 if (method->is_inflated && !mono_method_get_context (method)->method_inst) {
9513 ctx = &((MonoMethodInflated*)method)->context;
9514 method = ((MonoMethodInflated*)method)->declaring;
9515 container = mono_method_get_generic_container (method);
9516 if (!container)
9517 container = mono_class_try_get_generic_container (method->klass); //FIXME is this a case of a try?
9518 g_assert (container);
9519 }
9520
9521 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_UNKNOWN);
9522 #ifdef ENABLE_ILGEN
9523 mono_mb_emit_exception_full (mb, "System", "ExecutionEngineException", "Shouldn't be called.");
9524 mono_mb_emit_byte (mb, CEE_RET);
9525 #endif
9526 sig = mono_metadata_signature_dup_full (method->klass->image, mono_method_signature (method));
9527
9528 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_SYNCHRONIZED_INNER);
9529 info->d.synchronized_inner.method = method;
9530 res = mono_mb_create (mb, sig, 0, info);
9531 mono_mb_free (mb);
9532 if (ctx) {
9533 MonoError error;
9534 res = mono_class_inflate_generic_method_checked (res, ctx, &error);
9535 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
9536 }
9537 return res;
9538 }
9539
9540 /**
9541 * mono_marshal_get_synchronized_wrapper:
9542 * Generates IL code for the synchronized wrapper: the generated method
9543 * calls \p method while locking \c this or the parent type.
9544 */
9545 MonoMethod *
mono_marshal_get_synchronized_wrapper(MonoMethod * method)9546 mono_marshal_get_synchronized_wrapper (MonoMethod *method)
9547 {
9548 static MonoMethod *enter_method, *exit_method, *gettypefromhandle_method;
9549 MonoMethodSignature *sig;
9550 MonoExceptionClause *clause;
9551 MonoMethodBuilder *mb;
9552 MonoMethod *res;
9553 GHashTable *cache;
9554 WrapperInfo *info;
9555 int i, pos, pos2, this_local, taken_local, ret_local = 0;
9556 MonoGenericContext *ctx = NULL;
9557 MonoMethod *orig_method = NULL;
9558 MonoGenericContainer *container = NULL;
9559
9560 g_assert (method);
9561
9562 if (method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED)
9563 return method;
9564
9565 /* FIXME: Support generic methods too */
9566 if (method->is_inflated && !mono_method_get_context (method)->method_inst) {
9567 orig_method = method;
9568 ctx = &((MonoMethodInflated*)method)->context;
9569 method = ((MonoMethodInflated*)method)->declaring;
9570 container = mono_method_get_generic_container (method);
9571 if (!container)
9572 container = mono_class_try_get_generic_container (method->klass); //FIXME is this a case of a try?
9573 g_assert (container);
9574 }
9575
9576 /*
9577 * Check cache
9578 */
9579 if (ctx) {
9580 cache = get_cache (&((MonoMethodInflated*)orig_method)->owner->wrapper_caches.synchronized_cache, mono_aligned_addr_hash, NULL);
9581 res = check_generic_wrapper_cache (cache, orig_method, orig_method, method);
9582 if (res)
9583 return res;
9584 } else {
9585 cache = get_cache (&method->klass->image->wrapper_caches.synchronized_cache, mono_aligned_addr_hash, NULL);
9586 if ((res = mono_marshal_find_in_cache (cache, method)))
9587 return res;
9588 }
9589
9590 sig = mono_metadata_signature_dup_full (method->klass->image, mono_method_signature (method));
9591 sig->pinvoke = 0;
9592
9593 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_SYNCHRONIZED);
9594
9595 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NONE);
9596 info->d.synchronized.method = method;
9597
9598 #ifdef ENABLE_ILGEN
9599 mb->skip_visibility = 1;
9600 /* result */
9601 if (!MONO_TYPE_IS_VOID (sig->ret))
9602 ret_local = mono_mb_add_local (mb, sig->ret);
9603 #endif
9604
9605 if (method->klass->valuetype && !(method->flags & MONO_METHOD_ATTR_STATIC)) {
9606 /* FIXME Is this really the best way to signal an error here? Isn't this called much later after class setup? -AK */
9607 mono_class_set_type_load_failure (method->klass, "");
9608 #ifdef ENABLE_ILGEN
9609 /* This will throw the type load exception when the wrapper is compiled */
9610 mono_mb_emit_byte (mb, CEE_LDNULL);
9611 mono_mb_emit_op (mb, CEE_ISINST, method->klass);
9612 mono_mb_emit_byte (mb, CEE_POP);
9613
9614 if (!MONO_TYPE_IS_VOID (sig->ret))
9615 mono_mb_emit_ldloc (mb, ret_local);
9616 mono_mb_emit_byte (mb, CEE_RET);
9617 #endif
9618
9619 res = mono_mb_create_and_cache_full (cache, method,
9620 mb, sig, sig->param_count + 16, info, NULL);
9621 mono_mb_free (mb);
9622
9623 return res;
9624 }
9625
9626 #ifdef ENABLE_ILGEN
9627 /* this */
9628 this_local = mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
9629 taken_local = mono_mb_add_local (mb, &mono_defaults.boolean_class->byval_arg);
9630
9631 clause = (MonoExceptionClause *)mono_image_alloc0 (method->klass->image, sizeof (MonoExceptionClause));
9632 clause->flags = MONO_EXCEPTION_CLAUSE_FINALLY;
9633 #endif
9634
9635 mono_marshal_lock ();
9636
9637 if (!enter_method) {
9638 MonoMethodDesc *desc;
9639
9640 desc = mono_method_desc_new ("Monitor:Enter(object,bool&)", FALSE);
9641 enter_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
9642 g_assert (enter_method);
9643 mono_method_desc_free (desc);
9644
9645 desc = mono_method_desc_new ("Monitor:Exit", FALSE);
9646 exit_method = mono_method_desc_search_in_class (desc, mono_defaults.monitor_class);
9647 g_assert (exit_method);
9648 mono_method_desc_free (desc);
9649
9650 desc = mono_method_desc_new ("Type:GetTypeFromHandle", FALSE);
9651 gettypefromhandle_method = mono_method_desc_search_in_class (desc, mono_defaults.systemtype_class);
9652 g_assert (gettypefromhandle_method);
9653 mono_method_desc_free (desc);
9654 }
9655
9656 mono_marshal_unlock ();
9657
9658 #ifdef ENABLE_ILGEN
9659 /* Push this or the type object */
9660 if (method->flags & METHOD_ATTRIBUTE_STATIC) {
9661 /* We have special handling for this in the JIT */
9662 int index = mono_mb_add_data (mb, method->klass);
9663 mono_mb_add_data (mb, mono_defaults.typehandle_class);
9664 mono_mb_emit_byte (mb, CEE_LDTOKEN);
9665 mono_mb_emit_i4 (mb, index);
9666
9667 mono_mb_emit_managed_call (mb, gettypefromhandle_method, NULL);
9668 }
9669 else
9670 mono_mb_emit_ldarg (mb, 0);
9671 mono_mb_emit_stloc (mb, this_local);
9672
9673 /* Call Monitor::Enter() */
9674 mono_mb_emit_ldloc (mb, this_local);
9675 mono_mb_emit_ldloc_addr (mb, taken_local);
9676 mono_mb_emit_managed_call (mb, enter_method, NULL);
9677
9678 clause->try_offset = mono_mb_get_label (mb);
9679
9680 /* Call the method */
9681 if (sig->hasthis)
9682 mono_mb_emit_ldarg (mb, 0);
9683 for (i = 0; i < sig->param_count; i++)
9684 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
9685
9686 if (ctx) {
9687 MonoError error;
9688 mono_mb_emit_managed_call (mb, mono_class_inflate_generic_method_checked (method, &container->context, &error), NULL);
9689 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
9690 } else {
9691 mono_mb_emit_managed_call (mb, method, NULL);
9692 }
9693
9694 if (!MONO_TYPE_IS_VOID (sig->ret))
9695 mono_mb_emit_stloc (mb, ret_local);
9696
9697 pos = mono_mb_emit_branch (mb, CEE_LEAVE);
9698
9699 clause->try_len = mono_mb_get_pos (mb) - clause->try_offset;
9700 clause->handler_offset = mono_mb_get_label (mb);
9701
9702 /* Call Monitor::Exit() if needed */
9703 mono_mb_emit_ldloc (mb, taken_local);
9704 pos2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
9705 mono_mb_emit_ldloc (mb, this_local);
9706 mono_mb_emit_managed_call (mb, exit_method, NULL);
9707 mono_mb_patch_branch (mb, pos2);
9708 mono_mb_emit_byte (mb, CEE_ENDFINALLY);
9709
9710 clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset;
9711
9712 mono_mb_patch_branch (mb, pos);
9713 if (!MONO_TYPE_IS_VOID (sig->ret))
9714 mono_mb_emit_ldloc (mb, ret_local);
9715 mono_mb_emit_byte (mb, CEE_RET);
9716
9717 mono_mb_set_clauses (mb, 1, clause);
9718 #endif
9719
9720 if (ctx) {
9721 MonoMethod *def;
9722 def = mono_mb_create_and_cache_full (cache, method, mb, sig, sig->param_count + 16, info, NULL);
9723 res = cache_generic_wrapper (cache, orig_method, def, ctx, orig_method);
9724 } else {
9725 res = mono_mb_create_and_cache_full (cache, method,
9726 mb, sig, sig->param_count + 16, info, NULL);
9727 }
9728 mono_mb_free (mb);
9729
9730 return res;
9731 }
9732
9733
9734 /**
9735 * mono_marshal_get_unbox_wrapper:
9736 * The returned method calls \p method unboxing the \c this argument.
9737 */
9738 MonoMethod *
mono_marshal_get_unbox_wrapper(MonoMethod * method)9739 mono_marshal_get_unbox_wrapper (MonoMethod *method)
9740 {
9741 MonoMethodSignature *sig = mono_method_signature (method);
9742 int i;
9743 MonoMethodBuilder *mb;
9744 MonoMethod *res;
9745 GHashTable *cache;
9746 WrapperInfo *info;
9747
9748 cache = get_cache (&mono_method_get_wrapper_cache (method)->unbox_wrapper_cache, mono_aligned_addr_hash, NULL);
9749
9750 if ((res = mono_marshal_find_in_cache (cache, method)))
9751 return res;
9752
9753 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_UNBOX);
9754
9755 g_assert (sig->hasthis);
9756
9757 #ifdef ENABLE_ILGEN
9758 mono_mb_emit_ldarg (mb, 0);
9759 mono_mb_emit_icon (mb, sizeof (MonoObject));
9760 mono_mb_emit_byte (mb, CEE_ADD);
9761 for (i = 0; i < sig->param_count; ++i)
9762 mono_mb_emit_ldarg (mb, i + 1);
9763 mono_mb_emit_managed_call (mb, method, NULL);
9764 mono_mb_emit_byte (mb, CEE_RET);
9765 #endif
9766
9767 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NONE);
9768 info->d.unbox.method = method;
9769
9770 res = mono_mb_create_and_cache_full (cache, method,
9771 mb, sig, sig->param_count + 16, info, NULL);
9772 mono_mb_free (mb);
9773
9774 /* mono_method_print_code (res); */
9775
9776 return res;
9777 }
9778
9779 enum {
9780 STELEMREF_OBJECT, /*no check at all*/
9781 STELEMREF_SEALED_CLASS, /*check vtable->klass->element_type */
9782 STELEMREF_CLASS, /*only the klass->parents check*/
9783 STELEMREF_CLASS_SMALL_IDEPTH, /* like STELEMREF_CLASS bit without the idepth check */
9784 STELEMREF_INTERFACE, /*interfaces without variant generic arguments. */
9785 STELEMREF_COMPLEX, /*arrays, MBR or types with variant generic args - go straight to icalls*/
9786 STELEMREF_KIND_COUNT
9787 };
9788
9789 static const char *strelemref_wrapper_name[] = {
9790 "object", "sealed_class", "class", "class_small_idepth", "interface", "complex"
9791 };
9792
9793 static gboolean
is_monomorphic_array(MonoClass * klass)9794 is_monomorphic_array (MonoClass *klass)
9795 {
9796 MonoClass *element_class;
9797 if (klass->rank != 1)
9798 return FALSE;
9799
9800 element_class = klass->element_class;
9801 return mono_class_is_sealed (element_class) || element_class->valuetype;
9802 }
9803
9804 static int
get_virtual_stelemref_kind(MonoClass * element_class)9805 get_virtual_stelemref_kind (MonoClass *element_class)
9806 {
9807 if (element_class == mono_defaults.object_class)
9808 return STELEMREF_OBJECT;
9809 if (is_monomorphic_array (element_class))
9810 return STELEMREF_SEALED_CLASS;
9811 /* Compressed interface bitmaps require code that is quite complex, so don't optimize for it. */
9812 if (MONO_CLASS_IS_INTERFACE (element_class) && !mono_class_has_variant_generic_params (element_class))
9813 #ifdef COMPRESSED_INTERFACE_BITMAP
9814 return STELEMREF_COMPLEX;
9815 #else
9816 return STELEMREF_INTERFACE;
9817 #endif
9818 /*Arrays are sealed but are covariant on their element type, We can't use any of the fast paths.*/
9819 if (mono_class_is_marshalbyref (element_class) || element_class->rank || mono_class_has_variant_generic_params (element_class))
9820 return STELEMREF_COMPLEX;
9821 if (mono_class_is_sealed (element_class))
9822 return STELEMREF_SEALED_CLASS;
9823 if (element_class->idepth <= MONO_DEFAULT_SUPERTABLE_SIZE)
9824 return STELEMREF_CLASS_SMALL_IDEPTH;
9825
9826 return STELEMREF_CLASS;
9827 }
9828
9829 #ifdef ENABLE_ILGEN
9830
9831 static void
load_array_element_address(MonoMethodBuilder * mb)9832 load_array_element_address (MonoMethodBuilder *mb)
9833 {
9834 mono_mb_emit_ldarg (mb, 0);
9835 mono_mb_emit_ldarg (mb, 1);
9836 mono_mb_emit_op (mb, CEE_LDELEMA, mono_defaults.object_class);
9837 }
9838
9839 static void
load_array_class(MonoMethodBuilder * mb,int aklass)9840 load_array_class (MonoMethodBuilder *mb, int aklass)
9841 {
9842 mono_mb_emit_ldarg (mb, 0);
9843 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoObject, vtable));
9844 mono_mb_emit_byte (mb, CEE_LDIND_I);
9845 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoVTable, klass));
9846 mono_mb_emit_byte (mb, CEE_LDIND_I);
9847 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoClass, element_class));
9848 mono_mb_emit_byte (mb, CEE_LDIND_I);
9849 mono_mb_emit_stloc (mb, aklass);
9850 }
9851
9852 static void
load_value_class(MonoMethodBuilder * mb,int vklass)9853 load_value_class (MonoMethodBuilder *mb, int vklass)
9854 {
9855 mono_mb_emit_ldarg (mb, 2);
9856 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoObject, vtable));
9857 mono_mb_emit_byte (mb, CEE_LDIND_I);
9858 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoVTable, klass));
9859 mono_mb_emit_byte (mb, CEE_LDIND_I);
9860 mono_mb_emit_stloc (mb, vklass);
9861 }
9862 #endif
9863
9864 #if 0
9865 static void
9866 record_slot_vstore (MonoObject *array, size_t index, MonoObject *value)
9867 {
9868 char *name = mono_type_get_full_name (array->vtable->klass->element_class);
9869 printf ("slow vstore of %s\n", name);
9870 g_free (name);
9871 }
9872 #endif
9873
9874 /*
9875 * TODO:
9876 * - Separate simple interfaces from variant interfaces or mbr types. This way we can avoid the icall for them.
9877 * - Emit a (new) mono bytecode that produces OP_COND_EXC_NE_UN to raise ArrayTypeMismatch
9878 * - Maybe mve some MonoClass field into the vtable to reduce the number of loads
9879 * - Add a case for arrays of arrays.
9880 */
9881 static MonoMethod*
get_virtual_stelemref_wrapper(int kind)9882 get_virtual_stelemref_wrapper (int kind)
9883 {
9884 static MonoMethod *cached_methods [STELEMREF_KIND_COUNT] = { NULL }; /*object iface sealed regular*/
9885 static MonoMethodSignature *signature;
9886 MonoMethodBuilder *mb;
9887 MonoMethod *res;
9888 char *name;
9889 const char *param_names [16];
9890 guint32 b1, b2, b3, b4;
9891 int aklass, vklass, vtable, uiid;
9892 int array_slot_addr;
9893 WrapperInfo *info;
9894
9895 if (cached_methods [kind])
9896 return cached_methods [kind];
9897
9898 name = g_strdup_printf ("virt_stelemref_%s", strelemref_wrapper_name [kind]);
9899 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_STELEMREF);
9900 g_free (name);
9901
9902 if (!signature) {
9903 MonoMethodSignature *sig = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
9904
9905 /* void this::stelemref (size_t idx, void* value) */
9906 sig->ret = &mono_defaults.void_class->byval_arg;
9907 sig->hasthis = TRUE;
9908 sig->params [0] = &mono_defaults.int_class->byval_arg; /* this is a natural sized int */
9909 sig->params [1] = &mono_defaults.object_class->byval_arg;
9910 signature = sig;
9911 }
9912
9913 #ifdef ENABLE_ILGEN
9914 param_names [0] = "index";
9915 param_names [1] = "value";
9916 mono_mb_set_param_names (mb, param_names);
9917
9918 /*For now simply call plain old stelemref*/
9919 switch (kind) {
9920 case STELEMREF_OBJECT:
9921 /* ldelema (implicit bound check) */
9922 load_array_element_address (mb);
9923 /* do_store */
9924 mono_mb_emit_ldarg (mb, 2);
9925 mono_mb_emit_byte (mb, CEE_STIND_REF);
9926 mono_mb_emit_byte (mb, CEE_RET);
9927 break;
9928
9929 case STELEMREF_COMPLEX: {
9930 int b_fast;
9931 /*
9932 <ldelema (bound check)>
9933 if (!value)
9934 goto store;
9935 if (!mono_object_isinst (value, aklass))
9936 goto do_exception;
9937
9938 do_store:
9939 *array_slot_addr = value;
9940
9941 do_exception:
9942 throw new ArrayTypeMismatchException ();
9943 */
9944
9945 aklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
9946 vklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
9947 array_slot_addr = mono_mb_add_local (mb, &mono_defaults.object_class->this_arg);
9948
9949 #if 0
9950 {
9951 /*Use this to debug/record stores that are going thru the slow path*/
9952 MonoMethodSignature *csig;
9953 csig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
9954 csig->ret = &mono_defaults.void_class->byval_arg;
9955 csig->params [0] = &mono_defaults.object_class->byval_arg;
9956 csig->params [1] = &mono_defaults.int_class->byval_arg; /* this is a natural sized int */
9957 csig->params [2] = &mono_defaults.object_class->byval_arg;
9958 mono_mb_emit_ldarg (mb, 0);
9959 mono_mb_emit_ldarg (mb, 1);
9960 mono_mb_emit_ldarg (mb, 2);
9961 mono_mb_emit_native_call (mb, csig, record_slot_vstore);
9962 }
9963 #endif
9964
9965 /* ldelema (implicit bound check) */
9966 load_array_element_address (mb);
9967 mono_mb_emit_stloc (mb, array_slot_addr);
9968
9969 /* if (!value) goto do_store */
9970 mono_mb_emit_ldarg (mb, 2);
9971 b1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
9972
9973 /* aklass = array->vtable->klass->element_class */
9974 load_array_class (mb, aklass);
9975 /* vklass = value->vtable->klass */
9976 load_value_class (mb, vklass);
9977
9978 /* fastpath */
9979 mono_mb_emit_ldloc (mb, vklass);
9980 mono_mb_emit_ldloc (mb, aklass);
9981 b_fast = mono_mb_emit_branch (mb, CEE_BEQ);
9982
9983 /*if (mono_object_isinst (value, aklass)) */
9984 mono_mb_emit_ldarg (mb, 2);
9985 mono_mb_emit_ldloc (mb, aklass);
9986 mono_mb_emit_icall (mb, mono_object_isinst_icall);
9987 b2 = mono_mb_emit_branch (mb, CEE_BRFALSE);
9988
9989 /* do_store: */
9990 mono_mb_patch_branch (mb, b1);
9991 mono_mb_patch_branch (mb, b_fast);
9992 mono_mb_emit_ldloc (mb, array_slot_addr);
9993 mono_mb_emit_ldarg (mb, 2);
9994 mono_mb_emit_byte (mb, CEE_STIND_REF);
9995 mono_mb_emit_byte (mb, CEE_RET);
9996
9997 /* do_exception: */
9998 mono_mb_patch_branch (mb, b2);
9999
10000 mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL);
10001 break;
10002 }
10003 case STELEMREF_SEALED_CLASS:
10004 /*
10005 <ldelema (bound check)>
10006 if (!value)
10007 goto store;
10008
10009 aklass = array->vtable->klass->element_class;
10010 vklass = value->vtable->klass;
10011
10012 if (vklass != aklass)
10013 goto do_exception;
10014
10015 do_store:
10016 *array_slot_addr = value;
10017
10018 do_exception:
10019 throw new ArrayTypeMismatchException ();
10020 */
10021 aklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
10022 vklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
10023 array_slot_addr = mono_mb_add_local (mb, &mono_defaults.object_class->this_arg);
10024
10025 /* ldelema (implicit bound check) */
10026 load_array_element_address (mb);
10027 mono_mb_emit_stloc (mb, array_slot_addr);
10028
10029 /* if (!value) goto do_store */
10030 mono_mb_emit_ldarg (mb, 2);
10031 b1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
10032
10033 /* aklass = array->vtable->klass->element_class */
10034 load_array_class (mb, aklass);
10035
10036 /* vklass = value->vtable->klass */
10037 load_value_class (mb, vklass);
10038
10039 /*if (vklass != aklass) goto do_exception; */
10040 mono_mb_emit_ldloc (mb, aklass);
10041 mono_mb_emit_ldloc (mb, vklass);
10042 b2 = mono_mb_emit_branch (mb, CEE_BNE_UN);
10043
10044 /* do_store: */
10045 mono_mb_patch_branch (mb, b1);
10046 mono_mb_emit_ldloc (mb, array_slot_addr);
10047 mono_mb_emit_ldarg (mb, 2);
10048 mono_mb_emit_byte (mb, CEE_STIND_REF);
10049 mono_mb_emit_byte (mb, CEE_RET);
10050
10051 /* do_exception: */
10052 mono_mb_patch_branch (mb, b2);
10053 mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL);
10054 break;
10055
10056 case STELEMREF_CLASS: {
10057 /*
10058 the method:
10059 <ldelema (bound check)>
10060 if (!value)
10061 goto do_store;
10062
10063 aklass = array->vtable->klass->element_class;
10064 vklass = value->vtable->klass;
10065
10066 if (vklass->idepth < aklass->idepth)
10067 goto do_exception;
10068
10069 if (vklass->supertypes [aklass->idepth - 1] != aklass)
10070 goto do_exception;
10071
10072 do_store:
10073 *array_slot_addr = value;
10074 return;
10075
10076 long:
10077 throw new ArrayTypeMismatchException ();
10078 */
10079 aklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
10080 vklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
10081 array_slot_addr = mono_mb_add_local (mb, &mono_defaults.object_class->this_arg);
10082
10083 /* ldelema (implicit bound check) */
10084 load_array_element_address (mb);
10085 mono_mb_emit_stloc (mb, array_slot_addr);
10086
10087 /* if (!value) goto do_store */
10088 mono_mb_emit_ldarg (mb, 2);
10089 b1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
10090
10091 /* aklass = array->vtable->klass->element_class */
10092 load_array_class (mb, aklass);
10093
10094 /* vklass = value->vtable->klass */
10095 load_value_class (mb, vklass);
10096
10097 /* if (vklass->idepth < aklass->idepth) goto failue */
10098 mono_mb_emit_ldloc (mb, vklass);
10099 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoClass, idepth));
10100 mono_mb_emit_byte (mb, CEE_LDIND_U2);
10101
10102 mono_mb_emit_ldloc (mb, aklass);
10103 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoClass, idepth));
10104 mono_mb_emit_byte (mb, CEE_LDIND_U2);
10105
10106 b3 = mono_mb_emit_branch (mb, CEE_BLT_UN);
10107
10108 /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
10109 mono_mb_emit_ldloc (mb, vklass);
10110 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoClass, supertypes));
10111 mono_mb_emit_byte (mb, CEE_LDIND_I);
10112
10113 mono_mb_emit_ldloc (mb, aklass);
10114 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoClass, idepth));
10115 mono_mb_emit_byte (mb, CEE_LDIND_U2);
10116 mono_mb_emit_icon (mb, 1);
10117 mono_mb_emit_byte (mb, CEE_SUB);
10118 mono_mb_emit_icon (mb, sizeof (void*));
10119 mono_mb_emit_byte (mb, CEE_MUL);
10120 mono_mb_emit_byte (mb, CEE_ADD);
10121 mono_mb_emit_byte (mb, CEE_LDIND_I);
10122
10123 mono_mb_emit_ldloc (mb, aklass);
10124 b4 = mono_mb_emit_branch (mb, CEE_BNE_UN);
10125
10126 /* do_store: */
10127 mono_mb_patch_branch (mb, b1);
10128 mono_mb_emit_ldloc (mb, array_slot_addr);
10129 mono_mb_emit_ldarg (mb, 2);
10130 mono_mb_emit_byte (mb, CEE_STIND_REF);
10131 mono_mb_emit_byte (mb, CEE_RET);
10132
10133 /* do_exception: */
10134 mono_mb_patch_branch (mb, b3);
10135 mono_mb_patch_branch (mb, b4);
10136
10137 mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL);
10138 break;
10139 }
10140
10141 case STELEMREF_CLASS_SMALL_IDEPTH:
10142 /*
10143 the method:
10144 <ldelema (bound check)>
10145 if (!value)
10146 goto do_store;
10147
10148 aklass = array->vtable->klass->element_class;
10149 vklass = value->vtable->klass;
10150
10151 if (vklass->supertypes [aklass->idepth - 1] != aklass)
10152 goto do_exception;
10153
10154 do_store:
10155 *array_slot_addr = value;
10156 return;
10157
10158 long:
10159 throw new ArrayTypeMismatchException ();
10160 */
10161 aklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
10162 vklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
10163 array_slot_addr = mono_mb_add_local (mb, &mono_defaults.object_class->this_arg);
10164
10165 /* ldelema (implicit bound check) */
10166 load_array_element_address (mb);
10167 mono_mb_emit_stloc (mb, array_slot_addr);
10168
10169 /* if (!value) goto do_store */
10170 mono_mb_emit_ldarg (mb, 2);
10171 b1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
10172
10173 /* aklass = array->vtable->klass->element_class */
10174 load_array_class (mb, aklass);
10175
10176 /* vklass = value->vtable->klass */
10177 load_value_class (mb, vklass);
10178
10179 /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
10180 mono_mb_emit_ldloc (mb, vklass);
10181 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoClass, supertypes));
10182 mono_mb_emit_byte (mb, CEE_LDIND_I);
10183
10184 mono_mb_emit_ldloc (mb, aklass);
10185 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoClass, idepth));
10186 mono_mb_emit_byte (mb, CEE_LDIND_U2);
10187 mono_mb_emit_icon (mb, 1);
10188 mono_mb_emit_byte (mb, CEE_SUB);
10189 mono_mb_emit_icon (mb, sizeof (void*));
10190 mono_mb_emit_byte (mb, CEE_MUL);
10191 mono_mb_emit_byte (mb, CEE_ADD);
10192 mono_mb_emit_byte (mb, CEE_LDIND_I);
10193
10194 mono_mb_emit_ldloc (mb, aklass);
10195 b4 = mono_mb_emit_branch (mb, CEE_BNE_UN);
10196
10197 /* do_store: */
10198 mono_mb_patch_branch (mb, b1);
10199 mono_mb_emit_ldloc (mb, array_slot_addr);
10200 mono_mb_emit_ldarg (mb, 2);
10201 mono_mb_emit_byte (mb, CEE_STIND_REF);
10202 mono_mb_emit_byte (mb, CEE_RET);
10203
10204 /* do_exception: */
10205 mono_mb_patch_branch (mb, b4);
10206
10207 mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL);
10208 break;
10209
10210 case STELEMREF_INTERFACE:
10211 /*Mono *klass;
10212 MonoVTable *vt;
10213 unsigned uiid;
10214 if (value == NULL)
10215 goto store;
10216
10217 klass = array->obj.vtable->klass->element_class;
10218 vt = value->vtable;
10219 uiid = klass->interface_id;
10220 if (uiid > vt->max_interface_id)
10221 goto exception;
10222 if (!(vt->interface_bitmap [(uiid) >> 3] & (1 << ((uiid)&7))))
10223 goto exception;
10224 store:
10225 mono_array_setref (array, index, value);
10226 return;
10227 exception:
10228 mono_raise_exception (mono_get_exception_array_type_mismatch ());*/
10229
10230 array_slot_addr = mono_mb_add_local (mb, &mono_defaults.object_class->this_arg);
10231 aklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
10232 vtable = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
10233 uiid = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
10234
10235 /* ldelema (implicit bound check) */
10236 load_array_element_address (mb);
10237 mono_mb_emit_stloc (mb, array_slot_addr);
10238
10239 /* if (!value) goto do_store */
10240 mono_mb_emit_ldarg (mb, 2);
10241 b1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
10242
10243 /* klass = array->vtable->klass->element_class */
10244 load_array_class (mb, aklass);
10245
10246 /* vt = value->vtable */
10247 mono_mb_emit_ldarg (mb, 2);
10248 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoObject, vtable));
10249 mono_mb_emit_byte (mb, CEE_LDIND_I);
10250 mono_mb_emit_stloc (mb, vtable);
10251
10252 /* uiid = klass->interface_id; */
10253 mono_mb_emit_ldloc (mb, aklass);
10254 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoClass, interface_id));
10255 mono_mb_emit_byte (mb, CEE_LDIND_U4);
10256 mono_mb_emit_stloc (mb, uiid);
10257
10258 /*if (uiid > vt->max_interface_id)*/
10259 mono_mb_emit_ldloc (mb, uiid);
10260 mono_mb_emit_ldloc (mb, vtable);
10261 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
10262 mono_mb_emit_byte (mb, CEE_LDIND_U4);
10263 b2 = mono_mb_emit_branch (mb, CEE_BGT_UN);
10264
10265 /* if (!(vt->interface_bitmap [(uiid) >> 3] & (1 << ((uiid)&7)))) */
10266
10267 /*vt->interface_bitmap*/
10268 mono_mb_emit_ldloc (mb, vtable);
10269 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap));
10270 mono_mb_emit_byte (mb, CEE_LDIND_I);
10271
10272 /*uiid >> 3*/
10273 mono_mb_emit_ldloc (mb, uiid);
10274 mono_mb_emit_icon (mb, 3);
10275 mono_mb_emit_byte (mb, CEE_SHR_UN);
10276
10277 /*vt->interface_bitmap [(uiid) >> 3]*/
10278 mono_mb_emit_byte (mb, CEE_ADD); /*interface_bitmap is a guint8 array*/
10279 mono_mb_emit_byte (mb, CEE_LDIND_U1);
10280
10281 /*(1 << ((uiid)&7)))*/
10282 mono_mb_emit_icon (mb, 1);
10283 mono_mb_emit_ldloc (mb, uiid);
10284 mono_mb_emit_icon (mb, 7);
10285 mono_mb_emit_byte (mb, CEE_AND);
10286 mono_mb_emit_byte (mb, CEE_SHL);
10287
10288 /*bitwise and the whole thing*/
10289 mono_mb_emit_byte (mb, CEE_AND);
10290 b3 = mono_mb_emit_branch (mb, CEE_BRFALSE);
10291
10292 /* do_store: */
10293 mono_mb_patch_branch (mb, b1);
10294 mono_mb_emit_ldloc (mb, array_slot_addr);
10295 mono_mb_emit_ldarg (mb, 2);
10296 mono_mb_emit_byte (mb, CEE_STIND_REF);
10297 mono_mb_emit_byte (mb, CEE_RET);
10298
10299 /* do_exception: */
10300 mono_mb_patch_branch (mb, b2);
10301 mono_mb_patch_branch (mb, b3);
10302 mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL);
10303 break;
10304
10305 default:
10306 mono_mb_emit_ldarg (mb, 0);
10307 mono_mb_emit_ldarg (mb, 1);
10308 mono_mb_emit_ldarg (mb, 2);
10309 mono_mb_emit_managed_call (mb, mono_marshal_get_stelemref (), NULL);
10310 mono_mb_emit_byte (mb, CEE_RET);
10311 g_assert (0);
10312 }
10313 #endif /* ENABLE_ILGEN */
10314 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_VIRTUAL_STELEMREF);
10315 info->d.virtual_stelemref.kind = kind;
10316 res = mono_mb_create (mb, signature, 4, info);
10317 res->flags |= METHOD_ATTRIBUTE_VIRTUAL;
10318
10319 mono_marshal_lock ();
10320 if (!cached_methods [kind]) {
10321 cached_methods [kind] = res;
10322 mono_marshal_unlock ();
10323 } else {
10324 mono_marshal_unlock ();
10325 mono_free_method (res);
10326 }
10327
10328 mono_mb_free (mb);
10329 return cached_methods [kind];
10330 }
10331
10332 MonoMethod*
mono_marshal_get_virtual_stelemref(MonoClass * array_class)10333 mono_marshal_get_virtual_stelemref (MonoClass *array_class)
10334 {
10335 int kind;
10336
10337 g_assert (array_class->rank == 1);
10338 kind = get_virtual_stelemref_kind (array_class->element_class);
10339
10340 return get_virtual_stelemref_wrapper (kind);
10341 }
10342
10343 MonoMethod**
mono_marshal_get_virtual_stelemref_wrappers(int * nwrappers)10344 mono_marshal_get_virtual_stelemref_wrappers (int *nwrappers)
10345 {
10346 MonoMethod **res;
10347 int i;
10348
10349 *nwrappers = STELEMREF_KIND_COUNT;
10350 res = (MonoMethod **)g_malloc0 (STELEMREF_KIND_COUNT * sizeof (MonoMethod*));
10351 for (i = 0; i < STELEMREF_KIND_COUNT; ++i)
10352 res [i] = get_virtual_stelemref_wrapper (i);
10353 return res;
10354 }
10355
10356 /**
10357 * mono_marshal_get_stelemref:
10358 */
10359 MonoMethod*
mono_marshal_get_stelemref(void)10360 mono_marshal_get_stelemref (void)
10361 {
10362 static MonoMethod* ret = NULL;
10363 MonoMethodSignature *sig;
10364 MonoMethodBuilder *mb;
10365 WrapperInfo *info;
10366
10367 guint32 b1, b2, b3, b4;
10368 guint32 copy_pos;
10369 int aklass, vklass;
10370 int array_slot_addr;
10371
10372 if (ret)
10373 return ret;
10374
10375 mb = mono_mb_new (mono_defaults.object_class, "stelemref", MONO_WRAPPER_STELEMREF);
10376
10377
10378 sig = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
10379
10380 /* void stelemref (void* array, int idx, void* value) */
10381 sig->ret = &mono_defaults.void_class->byval_arg;
10382 sig->params [0] = &mono_defaults.object_class->byval_arg;
10383 sig->params [1] = &mono_defaults.int_class->byval_arg; /* this is a natural sized int */
10384 sig->params [2] = &mono_defaults.object_class->byval_arg;
10385
10386 #ifdef ENABLE_ILGEN
10387 aklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
10388 vklass = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
10389 array_slot_addr = mono_mb_add_local (mb, &mono_defaults.object_class->this_arg);
10390
10391 /*
10392 the method:
10393 <ldelema (bound check)>
10394 if (!value)
10395 goto store;
10396
10397 aklass = array->vtable->klass->element_class;
10398 vklass = value->vtable->klass;
10399
10400 if (vklass->idepth < aklass->idepth)
10401 goto long;
10402
10403 if (vklass->supertypes [aklass->idepth - 1] != aklass)
10404 goto long;
10405
10406 store:
10407 *array_slot_addr = value;
10408 return;
10409
10410 long:
10411 if (mono_object_isinst (value, aklass))
10412 goto store;
10413
10414 throw new ArrayTypeMismatchException ();
10415 */
10416
10417 /* ldelema (implicit bound check) */
10418 mono_mb_emit_ldarg (mb, 0);
10419 mono_mb_emit_ldarg (mb, 1);
10420 mono_mb_emit_op (mb, CEE_LDELEMA, mono_defaults.object_class);
10421 mono_mb_emit_stloc (mb, array_slot_addr);
10422
10423 /* if (!value) goto do_store */
10424 mono_mb_emit_ldarg (mb, 2);
10425 b1 = mono_mb_emit_branch (mb, CEE_BRFALSE);
10426
10427 /* aklass = array->vtable->klass->element_class */
10428 mono_mb_emit_ldarg (mb, 0);
10429 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoObject, vtable));
10430 mono_mb_emit_byte (mb, CEE_LDIND_I);
10431 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoVTable, klass));
10432 mono_mb_emit_byte (mb, CEE_LDIND_I);
10433 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoClass, element_class));
10434 mono_mb_emit_byte (mb, CEE_LDIND_I);
10435 mono_mb_emit_stloc (mb, aklass);
10436
10437 /* vklass = value->vtable->klass */
10438 mono_mb_emit_ldarg (mb, 2);
10439 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoObject, vtable));
10440 mono_mb_emit_byte (mb, CEE_LDIND_I);
10441 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoVTable, klass));
10442 mono_mb_emit_byte (mb, CEE_LDIND_I);
10443 mono_mb_emit_stloc (mb, vklass);
10444
10445 /* if (vklass->idepth < aklass->idepth) goto failue */
10446 mono_mb_emit_ldloc (mb, vklass);
10447 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoClass, idepth));
10448 mono_mb_emit_byte (mb, CEE_LDIND_U2);
10449
10450 mono_mb_emit_ldloc (mb, aklass);
10451 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoClass, idepth));
10452 mono_mb_emit_byte (mb, CEE_LDIND_U2);
10453
10454 b2 = mono_mb_emit_branch (mb, CEE_BLT_UN);
10455
10456 /* if (vklass->supertypes [aklass->idepth - 1] != aklass) goto failure */
10457 mono_mb_emit_ldloc (mb, vklass);
10458 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoClass, supertypes));
10459 mono_mb_emit_byte (mb, CEE_LDIND_I);
10460
10461 mono_mb_emit_ldloc (mb, aklass);
10462 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoClass, idepth));
10463 mono_mb_emit_byte (mb, CEE_LDIND_U2);
10464 mono_mb_emit_icon (mb, 1);
10465 mono_mb_emit_byte (mb, CEE_SUB);
10466 mono_mb_emit_icon (mb, sizeof (void*));
10467 mono_mb_emit_byte (mb, CEE_MUL);
10468 mono_mb_emit_byte (mb, CEE_ADD);
10469 mono_mb_emit_byte (mb, CEE_LDIND_I);
10470
10471 mono_mb_emit_ldloc (mb, aklass);
10472
10473 b3 = mono_mb_emit_branch (mb, CEE_BNE_UN);
10474
10475 copy_pos = mono_mb_get_label (mb);
10476 /* do_store */
10477 mono_mb_patch_branch (mb, b1);
10478 mono_mb_emit_ldloc (mb, array_slot_addr);
10479 mono_mb_emit_ldarg (mb, 2);
10480 mono_mb_emit_byte (mb, CEE_STIND_REF);
10481
10482 mono_mb_emit_byte (mb, CEE_RET);
10483
10484 /* the hard way */
10485 mono_mb_patch_branch (mb, b2);
10486 mono_mb_patch_branch (mb, b3);
10487
10488 mono_mb_emit_ldarg (mb, 2);
10489 mono_mb_emit_ldloc (mb, aklass);
10490 mono_mb_emit_icall (mb, mono_object_isinst_icall);
10491
10492 b4 = mono_mb_emit_branch (mb, CEE_BRTRUE);
10493 mono_mb_patch_addr (mb, b4, copy_pos - (b4 + 4));
10494 mono_mb_emit_exception (mb, "ArrayTypeMismatchException", NULL);
10495
10496 mono_mb_emit_byte (mb, CEE_RET);
10497 #endif
10498 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_NONE);
10499 ret = mono_mb_create (mb, sig, 4, info);
10500 mono_mb_free (mb);
10501
10502 return ret;
10503 }
10504
10505 /*
10506 * mono_marshal_get_gsharedvt_in_wrapper:
10507 *
10508 * This wrapper handles calls from normal code to gsharedvt code.
10509 */
10510 MonoMethod*
mono_marshal_get_gsharedvt_in_wrapper(void)10511 mono_marshal_get_gsharedvt_in_wrapper (void)
10512 {
10513 static MonoMethod* ret = NULL;
10514 MonoMethodSignature *sig;
10515 MonoMethodBuilder *mb;
10516 WrapperInfo *info;
10517
10518 if (ret)
10519 return ret;
10520
10521 mb = mono_mb_new (mono_defaults.object_class, "gsharedvt_in", MONO_WRAPPER_UNKNOWN);
10522
10523 sig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
10524 sig->ret = &mono_defaults.void_class->byval_arg;
10525
10526 #ifdef ENABLE_ILGEN
10527 /*
10528 * The body is generated by the JIT, we use a wrapper instead of a trampoline so EH works.
10529 */
10530 mono_mb_emit_byte (mb, CEE_RET);
10531 #endif
10532 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_IN);
10533 ret = mono_mb_create (mb, sig, 4, info);
10534 mono_mb_free (mb);
10535
10536 return ret;
10537 }
10538
10539 /*
10540 * mono_marshal_get_gsharedvt_out_wrapper:
10541 *
10542 * This wrapper handles calls from gsharedvt code to normal code.
10543 */
10544 MonoMethod*
mono_marshal_get_gsharedvt_out_wrapper(void)10545 mono_marshal_get_gsharedvt_out_wrapper (void)
10546 {
10547 static MonoMethod* ret = NULL;
10548 MonoMethodSignature *sig;
10549 MonoMethodBuilder *mb;
10550 WrapperInfo *info;
10551
10552 if (ret)
10553 return ret;
10554
10555 mb = mono_mb_new (mono_defaults.object_class, "gsharedvt_out", MONO_WRAPPER_UNKNOWN);
10556
10557 sig = mono_metadata_signature_alloc (mono_defaults.corlib, 0);
10558 sig->ret = &mono_defaults.void_class->byval_arg;
10559
10560 #ifdef ENABLE_ILGEN
10561 /*
10562 * The body is generated by the JIT, we use a wrapper instead of a trampoline so EH works.
10563 */
10564 mono_mb_emit_byte (mb, CEE_RET);
10565 #endif
10566 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GSHAREDVT_OUT);
10567 ret = mono_mb_create (mb, sig, 4, info);
10568 mono_mb_free (mb);
10569
10570 return ret;
10571 }
10572
10573 typedef struct {
10574 int rank;
10575 int elem_size;
10576 MonoMethod *method;
10577 } ArrayElemAddr;
10578
10579 /* LOCKING: vars accessed under the marshal lock */
10580 static ArrayElemAddr *elem_addr_cache = NULL;
10581 static int elem_addr_cache_size = 0;
10582 static int elem_addr_cache_next = 0;
10583
10584 /**
10585 * mono_marshal_get_array_address:
10586 * \param rank rank of the array type
10587 * \param elem_size size in bytes of an element of an array.
10588 *
10589 * Returns a MonoMethod that implements the code to get the address
10590 * of an element in a multi-dimenasional array of \p rank dimensions.
10591 * The returned method takes an array as the first argument and then
10592 * \p rank indexes for the \p rank dimensions.
10593 * If ELEM_SIZE is 0, read the array size from the array object.
10594 */
10595 MonoMethod*
mono_marshal_get_array_address(int rank,int elem_size)10596 mono_marshal_get_array_address (int rank, int elem_size)
10597 {
10598 MonoMethod *ret;
10599 MonoMethodBuilder *mb;
10600 MonoMethodSignature *sig;
10601 WrapperInfo *info;
10602 char *name;
10603 int i, bounds, ind, realidx;
10604 int branch_pos, *branch_positions;
10605 int cached;
10606
10607 ret = NULL;
10608 mono_marshal_lock ();
10609 for (i = 0; i < elem_addr_cache_next; ++i) {
10610 if (elem_addr_cache [i].rank == rank && elem_addr_cache [i].elem_size == elem_size) {
10611 ret = elem_addr_cache [i].method;
10612 break;
10613 }
10614 }
10615 mono_marshal_unlock ();
10616 if (ret)
10617 return ret;
10618
10619 branch_positions = g_new0 (int, rank);
10620
10621 sig = mono_metadata_signature_alloc (mono_defaults.corlib, 1 + rank);
10622
10623 /* void* address (void* array, int idx0, int idx1, int idx2, ...) */
10624 sig->ret = &mono_defaults.int_class->byval_arg;
10625 sig->params [0] = &mono_defaults.object_class->byval_arg;
10626 for (i = 0; i < rank; ++i) {
10627 sig->params [i + 1] = &mono_defaults.int32_class->byval_arg;
10628 }
10629
10630 name = g_strdup_printf ("ElementAddr_%d", elem_size);
10631 mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_MANAGED_TO_MANAGED);
10632 g_free (name);
10633
10634 #ifdef ENABLE_ILGEN
10635 bounds = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
10636 ind = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
10637 realidx = mono_mb_add_local (mb, &mono_defaults.int32_class->byval_arg);
10638
10639 /* bounds = array->bounds; */
10640 mono_mb_emit_ldarg (mb, 0);
10641 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoArray, bounds));
10642 mono_mb_emit_byte (mb, CEE_LDIND_I);
10643 mono_mb_emit_stloc (mb, bounds);
10644
10645 /* ind is the overall element index, realidx is the partial index in a single dimension */
10646 /* ind = idx0 - bounds [0].lower_bound */
10647 mono_mb_emit_ldarg (mb, 1);
10648 mono_mb_emit_ldloc (mb, bounds);
10649 mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
10650 mono_mb_emit_byte (mb, CEE_ADD);
10651 mono_mb_emit_byte (mb, CEE_LDIND_I4);
10652 mono_mb_emit_byte (mb, CEE_SUB);
10653 mono_mb_emit_stloc (mb, ind);
10654 /* if (ind >= bounds [0].length) goto exeception; */
10655 mono_mb_emit_ldloc (mb, ind);
10656 mono_mb_emit_ldloc (mb, bounds);
10657 mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
10658 mono_mb_emit_byte (mb, CEE_ADD);
10659 mono_mb_emit_byte (mb, CEE_LDIND_I4);
10660 /* note that we use unsigned comparison */
10661 branch_pos = mono_mb_emit_branch (mb, CEE_BGE_UN);
10662
10663 /* For large ranks (> 4?) use a loop n IL later to reduce code size.
10664 * We could also decide to ignore the passed elem_size and get it
10665 * from the array object, to reduce the number of methods we generate:
10666 * the additional cost is 3 memory loads and a non-immediate mul.
10667 */
10668 for (i = 1; i < rank; ++i) {
10669 /* realidx = idxi - bounds [i].lower_bound */
10670 mono_mb_emit_ldarg (mb, 1 + i);
10671 mono_mb_emit_ldloc (mb, bounds);
10672 mono_mb_emit_icon (mb, (i * sizeof (MonoArrayBounds)) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
10673 mono_mb_emit_byte (mb, CEE_ADD);
10674 mono_mb_emit_byte (mb, CEE_LDIND_I4);
10675 mono_mb_emit_byte (mb, CEE_SUB);
10676 mono_mb_emit_stloc (mb, realidx);
10677 /* if (realidx >= bounds [i].length) goto exeception; */
10678 mono_mb_emit_ldloc (mb, realidx);
10679 mono_mb_emit_ldloc (mb, bounds);
10680 mono_mb_emit_icon (mb, (i * sizeof (MonoArrayBounds)) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
10681 mono_mb_emit_byte (mb, CEE_ADD);
10682 mono_mb_emit_byte (mb, CEE_LDIND_I4);
10683 branch_positions [i] = mono_mb_emit_branch (mb, CEE_BGE_UN);
10684 /* ind = ind * bounds [i].length + realidx */
10685 mono_mb_emit_ldloc (mb, ind);
10686 mono_mb_emit_ldloc (mb, bounds);
10687 mono_mb_emit_icon (mb, (i * sizeof (MonoArrayBounds)) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
10688 mono_mb_emit_byte (mb, CEE_ADD);
10689 mono_mb_emit_byte (mb, CEE_LDIND_I4);
10690 mono_mb_emit_byte (mb, CEE_MUL);
10691 mono_mb_emit_ldloc (mb, realidx);
10692 mono_mb_emit_byte (mb, CEE_ADD);
10693 mono_mb_emit_stloc (mb, ind);
10694 }
10695
10696 /* return array->vector + ind * element_size */
10697 mono_mb_emit_ldarg (mb, 0);
10698 mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoArray, vector));
10699 mono_mb_emit_ldloc (mb, ind);
10700 if (elem_size) {
10701 mono_mb_emit_icon (mb, elem_size);
10702 } else {
10703 /* Load arr->vtable->klass->sizes.element_class */
10704 mono_mb_emit_ldarg (mb, 0);
10705 mono_mb_emit_byte (mb, CEE_CONV_I);
10706 mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoObject, vtable));
10707 mono_mb_emit_byte (mb, CEE_ADD);
10708 mono_mb_emit_byte (mb, CEE_LDIND_I);
10709 mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoVTable, klass));
10710 mono_mb_emit_byte (mb, CEE_ADD);
10711 mono_mb_emit_byte (mb, CEE_LDIND_I);
10712 /* sizes is an union, so this reads sizes.element_size */
10713 mono_mb_emit_icon (mb, MONO_STRUCT_OFFSET (MonoClass, sizes));
10714 mono_mb_emit_byte (mb, CEE_ADD);
10715 mono_mb_emit_byte (mb, CEE_LDIND_I4);
10716 }
10717 mono_mb_emit_byte (mb, CEE_MUL);
10718 mono_mb_emit_byte (mb, CEE_ADD);
10719 mono_mb_emit_byte (mb, CEE_RET);
10720
10721 /* patch the branches to get here and throw */
10722 for (i = 1; i < rank; ++i) {
10723 mono_mb_patch_branch (mb, branch_positions [i]);
10724 }
10725 mono_mb_patch_branch (mb, branch_pos);
10726 /* throw exception */
10727 mono_mb_emit_exception (mb, "IndexOutOfRangeException", NULL);
10728
10729 g_free (branch_positions);
10730 #endif /* ENABLE_ILGEN */
10731
10732 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_ELEMENT_ADDR);
10733 info->d.element_addr.rank = rank;
10734 info->d.element_addr.elem_size = elem_size;
10735 ret = mono_mb_create (mb, sig, 4, info);
10736 mono_mb_free (mb);
10737
10738 /* cache the result */
10739 cached = 0;
10740 mono_marshal_lock ();
10741 for (i = 0; i < elem_addr_cache_next; ++i) {
10742 if (elem_addr_cache [i].rank == rank && elem_addr_cache [i].elem_size == elem_size) {
10743 /* FIXME: free ret */
10744 ret = elem_addr_cache [i].method;
10745 cached = TRUE;
10746 break;
10747 }
10748 }
10749 if (!cached) {
10750 if (elem_addr_cache_next >= elem_addr_cache_size) {
10751 int new_size = elem_addr_cache_size + 4;
10752 ArrayElemAddr *new_array = g_new0 (ArrayElemAddr, new_size);
10753 memcpy (new_array, elem_addr_cache, elem_addr_cache_size * sizeof (ArrayElemAddr));
10754 g_free (elem_addr_cache);
10755 elem_addr_cache = new_array;
10756 elem_addr_cache_size = new_size;
10757 }
10758 elem_addr_cache [elem_addr_cache_next].rank = rank;
10759 elem_addr_cache [elem_addr_cache_next].elem_size = elem_size;
10760 elem_addr_cache [elem_addr_cache_next].method = ret;
10761 elem_addr_cache_next ++;
10762 }
10763 mono_marshal_unlock ();
10764 return ret;
10765 }
10766
10767 /*
10768 * mono_marshal_get_array_accessor_wrapper:
10769 *
10770 * Return a wrapper which just calls METHOD, which should be an Array Get/Set/Address method.
10771 */
10772 MonoMethod *
mono_marshal_get_array_accessor_wrapper(MonoMethod * method)10773 mono_marshal_get_array_accessor_wrapper (MonoMethod *method)
10774 {
10775 MonoMethodSignature *sig;
10776 MonoMethodBuilder *mb;
10777 MonoMethod *res;
10778 GHashTable *cache;
10779 int i;
10780 MonoGenericContext *ctx = NULL;
10781 MonoMethod *orig_method = NULL;
10782 MonoGenericContainer *container = NULL;
10783 WrapperInfo *info;
10784
10785 /*
10786 * These wrappers are needed to avoid the JIT replacing the calls to these methods with intrinsics
10787 * inside runtime invoke wrappers, thereby making the wrappers not unshareable.
10788 * FIXME: Use generic methods.
10789 */
10790 /*
10791 * Check cache
10792 */
10793 if (ctx) {
10794 cache = NULL;
10795 g_assert_not_reached ();
10796 } else {
10797 cache = get_cache (&method->klass->image->array_accessor_cache, mono_aligned_addr_hash, NULL);
10798 if ((res = mono_marshal_find_in_cache (cache, method)))
10799 return res;
10800 }
10801
10802 sig = mono_metadata_signature_dup_full (method->klass->image, mono_method_signature (method));
10803 sig->pinvoke = 0;
10804
10805 mb = mono_mb_new (method->klass, method->name, MONO_WRAPPER_UNKNOWN);
10806
10807 #ifdef ENABLE_ILGEN
10808 /* Call the method */
10809 if (sig->hasthis)
10810 mono_mb_emit_ldarg (mb, 0);
10811 for (i = 0; i < sig->param_count; i++)
10812 mono_mb_emit_ldarg (mb, i + (sig->hasthis == TRUE));
10813
10814 if (ctx) {
10815 MonoError error;
10816 mono_mb_emit_managed_call (mb, mono_class_inflate_generic_method_checked (method, &container->context, &error), NULL);
10817 g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
10818 } else {
10819 mono_mb_emit_managed_call (mb, method, NULL);
10820 }
10821 mono_mb_emit_byte (mb, CEE_RET);
10822 #endif
10823
10824 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_ARRAY_ACCESSOR);
10825 info->d.array_accessor.method = method;
10826
10827 if (ctx) {
10828 MonoMethod *def;
10829 def = mono_mb_create_and_cache_full (cache, method, mb, sig, sig->param_count + 16, info, NULL);
10830 res = cache_generic_wrapper (cache, orig_method, def, ctx, orig_method);
10831 } else {
10832 res = mono_mb_create_and_cache_full (cache, method,
10833 mb, sig, sig->param_count + 16,
10834 info, NULL);
10835 }
10836 mono_mb_free (mb);
10837
10838 return res;
10839 }
10840
10841 #ifndef HOST_WIN32
10842 static inline void*
mono_marshal_alloc_co_task_mem(size_t size)10843 mono_marshal_alloc_co_task_mem (size_t size)
10844 {
10845 if ((gulong)size == 0)
10846 /* This returns a valid pointer for size 0 on MS.NET */
10847 size = 4;
10848
10849 return g_try_malloc ((gulong)size);
10850 }
10851 #endif
10852
10853 /**
10854 * mono_marshal_alloc:
10855 */
10856 void*
mono_marshal_alloc(gsize size,MonoError * error)10857 mono_marshal_alloc (gsize size, MonoError *error)
10858 {
10859 gpointer res;
10860
10861 error_init (error);
10862
10863 res = mono_marshal_alloc_co_task_mem (size);
10864 if (!res)
10865 mono_error_set_out_of_memory (error, "Could not allocate %lu bytes", size);
10866
10867 return res;
10868 }
10869
10870 /* This is a JIT icall, it sets the pending exception and returns NULL on error. */
10871 static void*
ves_icall_marshal_alloc(gsize size)10872 ves_icall_marshal_alloc (gsize size)
10873 {
10874 MonoError error;
10875 void *ret = mono_marshal_alloc (size, &error);
10876 if (!mono_error_ok (&error)) {
10877 mono_error_set_pending_exception (&error);
10878 return NULL;
10879 }
10880
10881 return ret;
10882 }
10883
10884 #ifndef HOST_WIN32
10885 static inline void
mono_marshal_free_co_task_mem(void * ptr)10886 mono_marshal_free_co_task_mem (void *ptr)
10887 {
10888 g_free (ptr);
10889 return;
10890 }
10891 #endif
10892
10893 /**
10894 * mono_marshal_free:
10895 */
10896 void
mono_marshal_free(gpointer ptr)10897 mono_marshal_free (gpointer ptr)
10898 {
10899 mono_marshal_free_co_task_mem (ptr);
10900 }
10901
10902 /**
10903 * mono_marshal_free_array:
10904 */
10905 void
mono_marshal_free_array(gpointer * ptr,int size)10906 mono_marshal_free_array (gpointer *ptr, int size)
10907 {
10908 int i;
10909
10910 if (!ptr)
10911 return;
10912
10913 for (i = 0; i < size; i++)
10914 if (ptr [i])
10915 g_free (ptr [i]);
10916 }
10917
10918 void *
mono_marshal_string_to_utf16(MonoString * s)10919 mono_marshal_string_to_utf16 (MonoString *s)
10920 {
10921 return s ? mono_string_chars (s) : NULL;
10922 }
10923
10924 /* This is a JIT icall, it sets the pending exception and returns NULL on error. */
10925 static void *
mono_marshal_string_to_utf16_copy(MonoString * s)10926 mono_marshal_string_to_utf16_copy (MonoString *s)
10927 {
10928 if (s == NULL) {
10929 return NULL;
10930 } else {
10931 MonoError error;
10932 gunichar2 *res = (gunichar2 *)mono_marshal_alloc ((mono_string_length (s) * 2) + 2, &error);
10933 if (!mono_error_ok (&error)) {
10934 mono_error_set_pending_exception (&error);
10935 return NULL;
10936 }
10937 memcpy (res, mono_string_chars (s), mono_string_length (s) * 2);
10938 res [mono_string_length (s)] = 0;
10939 return res;
10940 }
10941 }
10942
10943 /**
10944 * mono_marshal_set_last_error:
10945 *
10946 * This function is invoked to set the last error value from a P/Invoke call
10947 * which has \c SetLastError set.
10948 */
10949 void
mono_marshal_set_last_error(void)10950 mono_marshal_set_last_error (void)
10951 {
10952 /* This icall is called just after a P/Invoke call before the P/Invoke
10953 * wrapper transitions the runtime back to running mode. */
10954 MONO_REQ_GC_SAFE_MODE;
10955 #ifdef WIN32
10956 mono_native_tls_set_value (last_error_tls_id, GINT_TO_POINTER (GetLastError ()));
10957 #else
10958 mono_native_tls_set_value (last_error_tls_id, GINT_TO_POINTER (errno));
10959 #endif
10960 }
10961
10962 static void
mono_marshal_set_last_error_windows(int error)10963 mono_marshal_set_last_error_windows (int error)
10964 {
10965 #ifdef WIN32
10966 /* This icall is called just after a P/Invoke call before the P/Invoke
10967 * wrapper transitions the runtime back to running mode. */
10968 MONO_REQ_GC_SAFE_MODE;
10969 mono_native_tls_set_value (last_error_tls_id, GINT_TO_POINTER (error));
10970 #endif
10971 }
10972
10973 void
ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged(MonoArray * src,gint32 start_index,gpointer dest,gint32 length)10974 ves_icall_System_Runtime_InteropServices_Marshal_copy_to_unmanaged (MonoArray *src, gint32 start_index,
10975 gpointer dest, gint32 length)
10976 {
10977 int element_size;
10978 void *source_addr;
10979
10980 MONO_CHECK_ARG_NULL (src,);
10981 MONO_CHECK_ARG_NULL (dest,);
10982
10983 if (src->obj.vtable->klass->rank != 1) {
10984 mono_set_pending_exception (mono_get_exception_argument ("array", "array is multi-dimensional"));
10985 return;
10986 }
10987 if (start_index < 0) {
10988 mono_set_pending_exception (mono_get_exception_argument ("startIndex", "Must be >= 0"));
10989 return;
10990 }
10991 if (length < 0) {
10992 mono_set_pending_exception (mono_get_exception_argument ("length", "Must be >= 0"));
10993 return;
10994 }
10995 if (start_index + length > mono_array_length (src)) {
10996 mono_set_pending_exception (mono_get_exception_argument ("length", "start_index + length > array length"));
10997 return;
10998 }
10999
11000 element_size = mono_array_element_size (src->obj.vtable->klass);
11001
11002 /* no references should be involved */
11003 source_addr = mono_array_addr_with_size_fast (src, element_size, start_index);
11004
11005 memcpy (dest, source_addr, length * element_size);
11006 }
11007
11008 void
ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged(gpointer src,gint32 start_index,MonoArray * dest,gint32 length)11009 ves_icall_System_Runtime_InteropServices_Marshal_copy_from_unmanaged (gpointer src, gint32 start_index,
11010 MonoArray *dest, gint32 length)
11011 {
11012 int element_size;
11013 void *dest_addr;
11014
11015 MONO_CHECK_ARG_NULL (src,);
11016 MONO_CHECK_ARG_NULL (dest,);
11017
11018 if (dest->obj.vtable->klass->rank != 1) {
11019 mono_set_pending_exception (mono_get_exception_argument ("array", "array is multi-dimensional"));
11020 return;
11021 }
11022 if (start_index < 0) {
11023 mono_set_pending_exception (mono_get_exception_argument ("startIndex", "Must be >= 0"));
11024 return;
11025 }
11026 if (length < 0) {
11027 mono_set_pending_exception (mono_get_exception_argument ("length", "Must be >= 0"));
11028 return;
11029 }
11030 if (start_index + length > mono_array_length (dest)) {
11031 mono_set_pending_exception (mono_get_exception_argument ("length", "start_index + length > array length"));
11032 return;
11033 }
11034 element_size = mono_array_element_size (dest->obj.vtable->klass);
11035
11036 /* no references should be involved */
11037 dest_addr = mono_array_addr_with_size_fast (dest, element_size, start_index);
11038
11039 memcpy (dest_addr, src, length * element_size);
11040 }
11041
11042 MonoStringHandle
ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi(char * ptr,MonoError * error)11043 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi (char *ptr, MonoError *error)
11044 {
11045 error_init (error);
11046 if (ptr == NULL)
11047 return MONO_HANDLE_CAST (MonoString, NULL_HANDLE);
11048 else
11049 return mono_string_new_handle (mono_domain_get (), ptr, error);
11050 }
11051
11052 MonoString *
ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len(char * ptr,gint32 len)11053 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringAnsi_len (char *ptr, gint32 len)
11054 {
11055 MonoError error;
11056 MonoString *result = NULL;
11057 error_init (&error);
11058 if (ptr == NULL)
11059 mono_error_set_argument_null (&error, "ptr", "");
11060 else
11061 result = mono_string_new_len_checked (mono_domain_get (), ptr, len, &error);
11062 mono_error_set_pending_exception (&error);
11063 return result;
11064 }
11065
11066 MonoString *
ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni(guint16 * ptr)11067 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni (guint16 *ptr)
11068 {
11069 MonoError error;
11070 MonoString *res = NULL;
11071 MonoDomain *domain = mono_domain_get ();
11072 int len = 0;
11073 guint16 *t = ptr;
11074
11075 if (ptr == NULL)
11076 return NULL;
11077
11078 while (*t++)
11079 len++;
11080
11081 res = mono_string_new_utf16_checked (domain, ptr, len, &error);
11082 if (!mono_error_ok (&error)) {
11083 mono_error_set_pending_exception (&error);
11084 return NULL;
11085 }
11086 return res;
11087 }
11088
11089 MonoString *
ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni_len(guint16 * ptr,gint32 len)11090 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStringUni_len (guint16 *ptr, gint32 len)
11091 {
11092 MonoError error;
11093 MonoString *res = NULL;
11094 MonoDomain *domain = mono_domain_get ();
11095
11096 error_init (&error);
11097
11098 if (ptr == NULL) {
11099 res = NULL;
11100 mono_error_set_argument_null (&error, "ptr", "");
11101 } else {
11102 res = mono_string_new_utf16_checked (domain, ptr, len, &error);
11103 }
11104
11105 if (!mono_error_ok (&error))
11106 mono_error_set_pending_exception (&error);
11107 return res;
11108 }
11109
11110 guint32
ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error(void)11111 ves_icall_System_Runtime_InteropServices_Marshal_GetLastWin32Error (void)
11112 {
11113 return (GPOINTER_TO_INT (mono_native_tls_get_value (last_error_tls_id)));
11114 }
11115
11116 guint32
ves_icall_System_Runtime_InteropServices_Marshal_SizeOf(MonoReflectionTypeHandle rtype,MonoError * error)11117 ves_icall_System_Runtime_InteropServices_Marshal_SizeOf (MonoReflectionTypeHandle rtype, MonoError *error)
11118 {
11119 MonoClass *klass;
11120 MonoType *type;
11121 guint32 layout;
11122
11123 error_init (error);
11124
11125 if (MONO_HANDLE_IS_NULL (rtype)) {
11126 mono_error_set_argument_null (error, "type", "");
11127 return 0;
11128 }
11129
11130 type = MONO_HANDLE_GETVAL (rtype, type);
11131 klass = mono_class_from_mono_type (type);
11132 if (!mono_class_init (klass)) {
11133 mono_error_set_for_class_failure (error, klass);
11134 return 0;
11135 }
11136
11137 layout = (mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK);
11138
11139 if (type->type == MONO_TYPE_PTR || type->type == MONO_TYPE_FNPTR) {
11140 return sizeof (gpointer);
11141 } else if (layout == TYPE_ATTRIBUTE_AUTO_LAYOUT) {
11142 mono_error_set_argument (error, "t", "Type %s cannot be marshaled as an unmanaged structure.", klass->name);
11143 return 0;
11144 }
11145
11146 return mono_class_native_size (klass, NULL);
11147 }
11148
11149 void
ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr(MonoObject * obj,gpointer dst,MonoBoolean delete_old)11150 ves_icall_System_Runtime_InteropServices_Marshal_StructureToPtr (MonoObject *obj, gpointer dst, MonoBoolean delete_old)
11151 {
11152 MonoError error;
11153 MonoMethod *method;
11154 gpointer pa [3];
11155
11156 MONO_CHECK_ARG_NULL (obj,);
11157 MONO_CHECK_ARG_NULL (dst,);
11158
11159 method = mono_marshal_get_struct_to_ptr (obj->vtable->klass);
11160
11161 pa [0] = obj;
11162 pa [1] = &dst;
11163 pa [2] = &delete_old;
11164
11165 mono_runtime_invoke_checked (method, NULL, pa, &error);
11166 if (!mono_error_ok (&error))
11167 mono_error_set_pending_exception (&error);
11168 }
11169
11170 static void
ptr_to_structure(gpointer src,MonoObject * dst,MonoError * error)11171 ptr_to_structure (gpointer src, MonoObject *dst, MonoError *error)
11172 {
11173 MonoMethod *method;
11174 gpointer pa [2];
11175
11176 error_init (error);
11177
11178 method = mono_marshal_get_ptr_to_struct (dst->vtable->klass);
11179
11180 pa [0] = &src;
11181 pa [1] = dst;
11182
11183 mono_runtime_invoke_checked (method, NULL, pa, error);
11184 }
11185
11186 void
ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure(gpointer src,MonoObject * dst)11187 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure (gpointer src, MonoObject *dst)
11188 {
11189 MonoType *t;
11190 MonoError error;
11191
11192 MONO_CHECK_ARG_NULL (src,);
11193 MONO_CHECK_ARG_NULL (dst,);
11194
11195 t = mono_type_get_underlying_type (mono_class_get_type (dst->vtable->klass));
11196
11197 if (t->type == MONO_TYPE_VALUETYPE) {
11198 MonoException *exc;
11199 gchar *tmp;
11200
11201 tmp = g_strdup_printf ("Destination is a boxed value type.");
11202 exc = mono_get_exception_argument ("dst", tmp);
11203 g_free (tmp);
11204
11205 mono_set_pending_exception (exc);
11206 return;
11207 }
11208
11209 ptr_to_structure (src, dst, &error);
11210 if (!mono_error_ok (&error))
11211 mono_error_set_pending_exception (&error);
11212 }
11213
11214 MonoObject *
ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type(gpointer src,MonoReflectionType * type)11215 ves_icall_System_Runtime_InteropServices_Marshal_PtrToStructure_type (gpointer src, MonoReflectionType *type)
11216 {
11217 MonoError error;
11218 MonoClass *klass;
11219 MonoDomain *domain = mono_domain_get ();
11220 MonoObject *res;
11221
11222 if (src == NULL)
11223 return NULL;
11224 MONO_CHECK_ARG_NULL (type, NULL);
11225
11226 klass = mono_class_from_mono_type (type->type);
11227 if (!mono_class_init (klass)) {
11228 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
11229 return NULL;
11230 }
11231
11232 res = mono_object_new_checked (domain, klass, &error);
11233 if (!mono_error_ok (&error)) {
11234 mono_error_set_pending_exception (&error);
11235 return NULL;
11236 }
11237
11238 ptr_to_structure (src, res, &error);
11239 if (!mono_error_ok (&error)) {
11240 mono_error_set_pending_exception (&error);
11241 return NULL;
11242 }
11243
11244 return res;
11245 }
11246
11247 int
ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf(MonoReflectionTypeHandle ref_type,MonoStringHandle field_name,MonoError * error)11248 ves_icall_System_Runtime_InteropServices_Marshal_OffsetOf (MonoReflectionTypeHandle ref_type, MonoStringHandle field_name, MonoError *error)
11249 {
11250 error_init (error);
11251 if (MONO_HANDLE_IS_NULL (ref_type)) {
11252 mono_error_set_argument_null (error, "type", "");
11253 return 0;
11254 }
11255 if (MONO_HANDLE_IS_NULL (field_name)) {
11256 mono_error_set_argument_null (error, "fieldName", "");
11257 return 0;
11258 }
11259
11260 char *fname = mono_string_handle_to_utf8 (field_name, error);
11261 return_val_if_nok (error, 0);
11262
11263 MonoType *type = MONO_HANDLE_GETVAL (ref_type, type);
11264 MonoClass *klass = mono_class_from_mono_type (type);
11265 if (!mono_class_init (klass)) {
11266 mono_error_set_for_class_failure (error, klass);
11267 return 0;
11268 }
11269
11270 int match_index = -1;
11271 while (klass && match_index == -1) {
11272 MonoClassField* field;
11273 int i = 0;
11274 gpointer iter = NULL;
11275 while ((field = mono_class_get_fields (klass, &iter))) {
11276 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
11277 continue;
11278 if (!strcmp (fname, mono_field_get_name (field))) {
11279 match_index = i;
11280 break;
11281 }
11282 i ++;
11283 }
11284
11285 if (match_index == -1)
11286 klass = klass->parent;
11287 }
11288
11289 g_free (fname);
11290
11291 if(match_index == -1) {
11292 /* Get back original class instance */
11293 klass = mono_class_from_mono_type (type);
11294
11295 mono_error_set_argument (error, "fieldName", "Field passed in is not a marshaled member of the type %s", klass->name);
11296 return 0;
11297 }
11298
11299 MonoMarshalType *info = mono_marshal_load_type_info (klass);
11300 return info->fields [match_index].offset;
11301 }
11302
11303 #ifndef HOST_WIN32
11304 gpointer
ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalAnsi(MonoString * string)11305 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalAnsi (MonoString *string)
11306 {
11307 MonoError error;
11308 char *ret = mono_string_to_utf8_checked (string, &error);
11309 mono_error_set_pending_exception (&error);
11310 return ret;
11311 }
11312
11313 gpointer
ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalUni(MonoString * string)11314 ves_icall_System_Runtime_InteropServices_Marshal_StringToHGlobalUni (MonoString *string)
11315 {
11316 if (string == NULL)
11317 return NULL;
11318 else {
11319 gunichar2 *res = (gunichar2 *)g_malloc ((mono_string_length (string) + 1) * 2);
11320
11321 memcpy (res, mono_string_chars (string), mono_string_length (string) * 2);
11322 res [mono_string_length (string)] = 0;
11323 return res;
11324 }
11325 }
11326 #endif /* !HOST_WIN32 */
11327
11328 static void
mono_struct_delete_old(MonoClass * klass,char * ptr)11329 mono_struct_delete_old (MonoClass *klass, char *ptr)
11330 {
11331 MonoMarshalType *info;
11332 int i;
11333
11334 info = mono_marshal_load_type_info (klass);
11335
11336 for (i = 0; i < info->num_fields; i++) {
11337 MonoMarshalConv conv;
11338 MonoType *ftype = info->fields [i].field->type;
11339 char *cpos;
11340
11341 if (ftype->attrs & FIELD_ATTRIBUTE_STATIC)
11342 continue;
11343
11344 mono_type_to_unmanaged (ftype, info->fields [i].mspec, TRUE,
11345 klass->unicode, &conv);
11346
11347 cpos = ptr + info->fields [i].offset;
11348
11349 switch (conv) {
11350 case MONO_MARSHAL_CONV_NONE:
11351 if (MONO_TYPE_ISSTRUCT (ftype)) {
11352 mono_struct_delete_old (ftype->data.klass, cpos);
11353 continue;
11354 }
11355 break;
11356 case MONO_MARSHAL_CONV_STR_LPWSTR:
11357 /* We assume this field points inside a MonoString */
11358 break;
11359 case MONO_MARSHAL_CONV_STR_LPTSTR:
11360 #ifdef TARGET_WIN32
11361 /* We assume this field points inside a MonoString
11362 * on Win32 */
11363 break;
11364 #endif
11365 case MONO_MARSHAL_CONV_STR_LPSTR:
11366 case MONO_MARSHAL_CONV_STR_BSTR:
11367 case MONO_MARSHAL_CONV_STR_ANSIBSTR:
11368 case MONO_MARSHAL_CONV_STR_TBSTR:
11369 case MONO_MARSHAL_CONV_STR_UTF8STR:
11370 mono_marshal_free (*(gpointer *)cpos);
11371 break;
11372
11373 default:
11374 continue;
11375 }
11376 }
11377 }
11378
11379 void
ves_icall_System_Runtime_InteropServices_Marshal_DestroyStructure(gpointer src,MonoReflectionType * type)11380 ves_icall_System_Runtime_InteropServices_Marshal_DestroyStructure (gpointer src, MonoReflectionType *type)
11381 {
11382 MonoClass *klass;
11383
11384 MONO_CHECK_ARG_NULL (src,);
11385 MONO_CHECK_ARG_NULL (type,);
11386
11387 klass = mono_class_from_mono_type (type->type);
11388 if (!mono_class_init (klass)) {
11389 mono_set_pending_exception (mono_class_get_exception_for_failure (klass));
11390 return;
11391 }
11392
11393 mono_struct_delete_old (klass, (char *)src);
11394 }
11395
11396 #ifndef HOST_WIN32
11397 static inline void *
mono_marshal_alloc_hglobal(size_t size)11398 mono_marshal_alloc_hglobal (size_t size)
11399 {
11400 return g_try_malloc (size);
11401 }
11402 #endif
11403
11404 void*
ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal(gpointer size)11405 ves_icall_System_Runtime_InteropServices_Marshal_AllocHGlobal (gpointer size)
11406 {
11407 gpointer res;
11408 size_t s = (size_t)size;
11409
11410 if (s == 0)
11411 /* This returns a valid pointer for size 0 on MS.NET */
11412 s = 4;
11413
11414 res = mono_marshal_alloc_hglobal (s);
11415
11416 if (!res) {
11417 mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex);
11418 return NULL;
11419 }
11420
11421 return res;
11422 }
11423
11424 #ifndef HOST_WIN32
11425 static inline gpointer
mono_marshal_realloc_hglobal(gpointer ptr,size_t size)11426 mono_marshal_realloc_hglobal (gpointer ptr, size_t size)
11427 {
11428 return g_try_realloc (ptr, size);
11429 }
11430 #endif
11431
11432 gpointer
ves_icall_System_Runtime_InteropServices_Marshal_ReAllocHGlobal(gpointer ptr,gpointer size)11433 ves_icall_System_Runtime_InteropServices_Marshal_ReAllocHGlobal (gpointer ptr, gpointer size)
11434 {
11435 gpointer res;
11436 size_t s = (size_t)size;
11437
11438 if (ptr == NULL) {
11439 mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex);
11440 return NULL;
11441 }
11442
11443 res = mono_marshal_realloc_hglobal (ptr, s);
11444
11445 if (!res) {
11446 mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex);
11447 return NULL;
11448 }
11449
11450 return res;
11451 }
11452
11453 #ifndef HOST_WIN32
11454 static inline void
mono_marshal_free_hglobal(gpointer ptr)11455 mono_marshal_free_hglobal (gpointer ptr)
11456 {
11457 g_free (ptr);
11458 return;
11459 }
11460 #endif
11461
11462 void
ves_icall_System_Runtime_InteropServices_Marshal_FreeHGlobal(void * ptr)11463 ves_icall_System_Runtime_InteropServices_Marshal_FreeHGlobal (void *ptr)
11464 {
11465 mono_marshal_free_hglobal (ptr);
11466 }
11467
11468 void*
ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMem(int size)11469 ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMem (int size)
11470 {
11471 void *res = mono_marshal_alloc_co_task_mem (size);
11472
11473 if (!res) {
11474 mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex);
11475 return NULL;
11476 }
11477 return res;
11478 }
11479
11480 void*
ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMemSize(gulong size)11481 ves_icall_System_Runtime_InteropServices_Marshal_AllocCoTaskMemSize (gulong size)
11482 {
11483 void *res = mono_marshal_alloc_co_task_mem (size);
11484
11485 if (!res) {
11486 mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex);
11487 return NULL;
11488 }
11489 return res;
11490 }
11491
11492 void
ves_icall_System_Runtime_InteropServices_Marshal_FreeCoTaskMem(void * ptr)11493 ves_icall_System_Runtime_InteropServices_Marshal_FreeCoTaskMem (void *ptr)
11494 {
11495 mono_marshal_free_co_task_mem (ptr);
11496 return;
11497 }
11498
11499 #ifndef HOST_WIN32
11500 static inline gpointer
mono_marshal_realloc_co_task_mem(gpointer ptr,size_t size)11501 mono_marshal_realloc_co_task_mem (gpointer ptr, size_t size)
11502 {
11503 return g_try_realloc (ptr, (gulong)size);
11504 }
11505 #endif
11506
11507 gpointer
ves_icall_System_Runtime_InteropServices_Marshal_ReAllocCoTaskMem(gpointer ptr,int size)11508 ves_icall_System_Runtime_InteropServices_Marshal_ReAllocCoTaskMem (gpointer ptr, int size)
11509 {
11510 void *res = mono_marshal_realloc_co_task_mem (ptr, size);
11511
11512 if (!res) {
11513 mono_set_pending_exception (mono_domain_get ()->out_of_memory_ex);
11514 return NULL;
11515 }
11516 return res;
11517 }
11518
11519 void*
ves_icall_System_Runtime_InteropServices_Marshal_UnsafeAddrOfPinnedArrayElement(MonoArray * arrayobj,int index)11520 ves_icall_System_Runtime_InteropServices_Marshal_UnsafeAddrOfPinnedArrayElement (MonoArray *arrayobj, int index)
11521 {
11522 return mono_array_addr_with_size_fast (arrayobj, mono_array_element_size (arrayobj->obj.vtable->klass), index);
11523 }
11524
11525 MonoDelegateHandle
ves_icall_System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointerInternal(void * ftn,MonoReflectionTypeHandle type,MonoError * error)11526 ves_icall_System_Runtime_InteropServices_Marshal_GetDelegateForFunctionPointerInternal (void *ftn, MonoReflectionTypeHandle type, MonoError *error)
11527 {
11528 error_init (error);
11529 MonoClass *klass = mono_type_get_class (MONO_HANDLE_GETVAL (type, type));
11530 if (!mono_class_init (klass)) {
11531 mono_error_set_for_class_failure (error, klass);
11532 return NULL;
11533 }
11534
11535 return mono_ftnptr_to_delegate_handle (klass, ftn, error);
11536 }
11537
11538 gpointer
ves_icall_System_Runtime_InteropServices_Marshal_GetFunctionPointerForDelegateInternal(MonoDelegateHandle delegate,MonoError * error)11539 ves_icall_System_Runtime_InteropServices_Marshal_GetFunctionPointerForDelegateInternal (MonoDelegateHandle delegate, MonoError *error)
11540 {
11541 error_init (error);
11542 return mono_delegate_handle_to_ftnptr (delegate, error);
11543 }
11544
11545 /**
11546 * mono_marshal_is_loading_type_info:
11547 *
11548 * Return whenever mono_marshal_load_type_info () is being executed for KLASS by this
11549 * thread.
11550 */
11551 static gboolean
mono_marshal_is_loading_type_info(MonoClass * klass)11552 mono_marshal_is_loading_type_info (MonoClass *klass)
11553 {
11554 GSList *loads_list = (GSList *)mono_native_tls_get_value (load_type_info_tls_id);
11555
11556 return g_slist_find (loads_list, klass) != NULL;
11557 }
11558
11559 /**
11560 * mono_marshal_load_type_info:
11561 *
11562 * Initialize \c klass::marshal_info using information from metadata. This function can
11563 * recursively call itself, and the caller is responsible to avoid that by calling
11564 * \c mono_marshal_is_loading_type_info beforehand.
11565 *
11566 * LOCKING: Acquires the loader lock.
11567 */
11568 MonoMarshalType *
mono_marshal_load_type_info(MonoClass * klass)11569 mono_marshal_load_type_info (MonoClass* klass)
11570 {
11571 int j, count = 0;
11572 guint32 native_size = 0, min_align = 1, packing;
11573 MonoMarshalType *info;
11574 MonoClassField* field;
11575 gpointer iter;
11576 guint32 layout;
11577 GSList *loads_list;
11578
11579 g_assert (klass != NULL);
11580
11581 info = mono_class_get_marshal_info (klass);
11582 if (info)
11583 return info;
11584
11585 if (!klass->inited)
11586 mono_class_init (klass);
11587
11588 info = mono_class_get_marshal_info (klass);
11589 if (info)
11590 return info;
11591
11592 /*
11593 * This function can recursively call itself, so we keep the list of classes which are
11594 * under initialization in a TLS list.
11595 */
11596 g_assert (!mono_marshal_is_loading_type_info (klass));
11597 loads_list = (GSList *)mono_native_tls_get_value (load_type_info_tls_id);
11598 loads_list = g_slist_prepend (loads_list, klass);
11599 mono_native_tls_set_value (load_type_info_tls_id, loads_list);
11600
11601 iter = NULL;
11602 while ((field = mono_class_get_fields (klass, &iter))) {
11603 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
11604 continue;
11605 if (mono_field_is_deleted (field))
11606 continue;
11607 count++;
11608 }
11609
11610 layout = mono_class_get_flags (klass) & TYPE_ATTRIBUTE_LAYOUT_MASK;
11611
11612 info = (MonoMarshalType *)mono_image_alloc0 (klass->image, MONO_SIZEOF_MARSHAL_TYPE + sizeof (MonoMarshalField) * count);
11613 info->num_fields = count;
11614
11615 /* Try to find a size for this type in metadata */
11616 mono_metadata_packing_from_typedef (klass->image, klass->type_token, NULL, &native_size);
11617
11618 if (klass->parent) {
11619 int parent_size = mono_class_native_size (klass->parent, NULL);
11620
11621 /* Add parent size to real size */
11622 native_size += parent_size;
11623 info->native_size = parent_size;
11624 }
11625
11626 packing = klass->packing_size ? klass->packing_size : 8;
11627 iter = NULL;
11628 j = 0;
11629 while ((field = mono_class_get_fields (klass, &iter))) {
11630 int size;
11631 guint32 align;
11632
11633 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
11634 continue;
11635
11636 if (mono_field_is_deleted (field))
11637 continue;
11638 if (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL)
11639 mono_metadata_field_info_with_mempool (klass->image, mono_metadata_token_index (mono_class_get_field_token (field)) - 1,
11640 NULL, NULL, &info->fields [j].mspec);
11641
11642 info->fields [j].field = field;
11643
11644 if ((mono_class_num_fields (klass) == 1) && (klass->instance_size == sizeof (MonoObject)) &&
11645 (strcmp (mono_field_get_name (field), "$PRIVATE$") == 0)) {
11646 /* This field is a hack inserted by MCS to empty structures */
11647 continue;
11648 }
11649
11650 switch (layout) {
11651 case TYPE_ATTRIBUTE_AUTO_LAYOUT:
11652 case TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT:
11653 size = mono_marshal_type_size (field->type, info->fields [j].mspec,
11654 &align, TRUE, klass->unicode);
11655 align = klass->packing_size ? MIN (klass->packing_size, align): align;
11656 min_align = MAX (align, min_align);
11657 info->fields [j].offset = info->native_size;
11658 info->fields [j].offset += align - 1;
11659 info->fields [j].offset &= ~(align - 1);
11660 info->native_size = info->fields [j].offset + size;
11661 break;
11662 case TYPE_ATTRIBUTE_EXPLICIT_LAYOUT:
11663 size = mono_marshal_type_size (field->type, info->fields [j].mspec,
11664 &align, TRUE, klass->unicode);
11665 min_align = MAX (align, min_align);
11666 info->fields [j].offset = field->offset - sizeof (MonoObject);
11667 info->native_size = MAX (info->native_size, info->fields [j].offset + size);
11668 break;
11669 }
11670 j++;
11671 }
11672
11673 if (klass->byval_arg.type == MONO_TYPE_PTR)
11674 info->native_size = sizeof (gpointer);
11675
11676 if (layout != TYPE_ATTRIBUTE_AUTO_LAYOUT) {
11677 info->native_size = MAX (native_size, info->native_size);
11678 /*
11679 * If the provided Size is equal or larger than the calculated size, and there
11680 * was no Pack attribute, we set min_align to 1 to avoid native_size being increased
11681 */
11682 if (layout == TYPE_ATTRIBUTE_EXPLICIT_LAYOUT) {
11683 if (native_size && native_size == info->native_size && klass->packing_size == 0)
11684 min_align = 1;
11685 else
11686 min_align = MIN (min_align, packing);
11687 }
11688 }
11689
11690 if (info->native_size & (min_align - 1)) {
11691 info->native_size += min_align - 1;
11692 info->native_size &= ~(min_align - 1);
11693 }
11694
11695 info->min_align = min_align;
11696
11697 /* Update the class's blittable info, if the layouts don't match */
11698 if (info->native_size != mono_class_value_size (klass, NULL)) {
11699 mono_loader_lock ();
11700 klass->blittable = FALSE;
11701 mono_loader_unlock ();
11702 }
11703
11704 /* If this is an array type, ensure that we have element info */
11705 if (klass->rank && !mono_marshal_is_loading_type_info (klass->element_class)) {
11706 mono_marshal_load_type_info (klass->element_class);
11707 }
11708
11709 loads_list = (GSList *)mono_native_tls_get_value (load_type_info_tls_id);
11710 loads_list = g_slist_remove (loads_list, klass);
11711 mono_native_tls_set_value (load_type_info_tls_id, loads_list);
11712
11713 mono_marshal_lock ();
11714 MonoMarshalType *info2 = mono_class_get_marshal_info (klass);
11715 if (!info2) {
11716 /*We do double-checking locking on marshal_info */
11717 mono_memory_barrier ();
11718 mono_class_set_marshal_info (klass, info);
11719 ++class_marshal_info_count;
11720 info2 = info;
11721 }
11722 mono_marshal_unlock ();
11723
11724 return info2;
11725 }
11726
11727 /**
11728 * mono_class_native_size:
11729 * \param klass a class
11730 * \returns the native size of an object instance (when marshaled
11731 * to unmanaged code)
11732 */
11733 gint32
mono_class_native_size(MonoClass * klass,guint32 * align)11734 mono_class_native_size (MonoClass *klass, guint32 *align)
11735 {
11736 MonoMarshalType *info = mono_class_get_marshal_info (klass);
11737 if (!info) {
11738 if (mono_marshal_is_loading_type_info (klass)) {
11739 if (align)
11740 *align = 0;
11741 return 0;
11742 } else {
11743 mono_marshal_load_type_info (klass);
11744 }
11745 info = mono_class_get_marshal_info (klass);
11746 }
11747
11748 if (align)
11749 *align = info->min_align;
11750
11751 return info->native_size;
11752 }
11753
11754 /*
11755 * mono_type_native_stack_size:
11756 * @t: the type to return the size it uses on the stack
11757 *
11758 * Returns: the number of bytes required to hold an instance of this
11759 * type on the native stack
11760 */
11761 int
mono_type_native_stack_size(MonoType * t,guint32 * align)11762 mono_type_native_stack_size (MonoType *t, guint32 *align)
11763 {
11764 guint32 tmp;
11765
11766 g_assert (t != NULL);
11767
11768 if (!align)
11769 align = &tmp;
11770
11771 if (t->byref) {
11772 *align = sizeof (gpointer);
11773 return sizeof (gpointer);
11774 }
11775
11776 switch (t->type){
11777 case MONO_TYPE_BOOLEAN:
11778 case MONO_TYPE_CHAR:
11779 case MONO_TYPE_I1:
11780 case MONO_TYPE_U1:
11781 case MONO_TYPE_I2:
11782 case MONO_TYPE_U2:
11783 case MONO_TYPE_I4:
11784 case MONO_TYPE_U4:
11785 *align = 4;
11786 return 4;
11787 case MONO_TYPE_I:
11788 case MONO_TYPE_U:
11789 case MONO_TYPE_STRING:
11790 case MONO_TYPE_OBJECT:
11791 case MONO_TYPE_CLASS:
11792 case MONO_TYPE_SZARRAY:
11793 case MONO_TYPE_PTR:
11794 case MONO_TYPE_FNPTR:
11795 case MONO_TYPE_ARRAY:
11796 *align = sizeof (gpointer);
11797 return sizeof (gpointer);
11798 case MONO_TYPE_R4:
11799 *align = 4;
11800 return 4;
11801 case MONO_TYPE_R8:
11802 *align = MONO_ABI_ALIGNOF (double);
11803 return 8;
11804 case MONO_TYPE_I8:
11805 case MONO_TYPE_U8:
11806 *align = MONO_ABI_ALIGNOF (gint64);
11807 return 8;
11808 case MONO_TYPE_GENERICINST:
11809 if (!mono_type_generic_inst_is_valuetype (t)) {
11810 *align = sizeof (gpointer);
11811 return sizeof (gpointer);
11812 }
11813 /* Fall through */
11814 case MONO_TYPE_TYPEDBYREF:
11815 case MONO_TYPE_VALUETYPE: {
11816 guint32 size;
11817 MonoClass *klass = mono_class_from_mono_type (t);
11818
11819 if (klass->enumtype)
11820 return mono_type_native_stack_size (mono_class_enum_basetype (klass), align);
11821 else {
11822 size = mono_class_native_size (klass, align);
11823 *align = *align + 3;
11824 *align &= ~3;
11825
11826 size += 3;
11827 size &= ~3;
11828
11829 return size;
11830 }
11831 }
11832 default:
11833 g_error ("type 0x%02x unknown", t->type);
11834 }
11835 return 0;
11836 }
11837
11838 /**
11839 * mono_marshal_type_size:
11840 */
11841 gint32
mono_marshal_type_size(MonoType * type,MonoMarshalSpec * mspec,guint32 * align,gboolean as_field,gboolean unicode)11842 mono_marshal_type_size (MonoType *type, MonoMarshalSpec *mspec, guint32 *align,
11843 gboolean as_field, gboolean unicode)
11844 {
11845 MonoMarshalNative native_type = mono_type_to_unmanaged (type, mspec, as_field, unicode, NULL);
11846 MonoClass *klass;
11847
11848 switch (native_type) {
11849 case MONO_NATIVE_BOOLEAN:
11850 *align = 4;
11851 return 4;
11852 case MONO_NATIVE_I1:
11853 case MONO_NATIVE_U1:
11854 *align = 1;
11855 return 1;
11856 case MONO_NATIVE_I2:
11857 case MONO_NATIVE_U2:
11858 case MONO_NATIVE_VARIANTBOOL:
11859 *align = 2;
11860 return 2;
11861 case MONO_NATIVE_I4:
11862 case MONO_NATIVE_U4:
11863 case MONO_NATIVE_ERROR:
11864 *align = 4;
11865 return 4;
11866 case MONO_NATIVE_I8:
11867 case MONO_NATIVE_U8:
11868 *align = MONO_ABI_ALIGNOF (gint64);
11869 return 8;
11870 case MONO_NATIVE_R4:
11871 *align = 4;
11872 return 4;
11873 case MONO_NATIVE_R8:
11874 *align = MONO_ABI_ALIGNOF (double);
11875 return 8;
11876 case MONO_NATIVE_INT:
11877 case MONO_NATIVE_UINT:
11878 case MONO_NATIVE_LPSTR:
11879 case MONO_NATIVE_LPWSTR:
11880 case MONO_NATIVE_LPTSTR:
11881 case MONO_NATIVE_BSTR:
11882 case MONO_NATIVE_ANSIBSTR:
11883 case MONO_NATIVE_TBSTR:
11884 case MONO_NATIVE_UTF8STR:
11885 case MONO_NATIVE_LPARRAY:
11886 case MONO_NATIVE_SAFEARRAY:
11887 case MONO_NATIVE_IUNKNOWN:
11888 case MONO_NATIVE_IDISPATCH:
11889 case MONO_NATIVE_INTERFACE:
11890 case MONO_NATIVE_ASANY:
11891 case MONO_NATIVE_FUNC:
11892 case MONO_NATIVE_LPSTRUCT:
11893 *align = MONO_ABI_ALIGNOF (gpointer);
11894 return sizeof (gpointer);
11895 case MONO_NATIVE_STRUCT:
11896 klass = mono_class_from_mono_type (type);
11897 if (klass == mono_defaults.object_class &&
11898 (mspec && mspec->native == MONO_NATIVE_STRUCT)) {
11899 *align = 16;
11900 return 16;
11901 }
11902 return mono_class_native_size (klass, align);
11903 case MONO_NATIVE_BYVALTSTR: {
11904 int esize = unicode ? 2: 1;
11905 g_assert (mspec);
11906 *align = esize;
11907 return mspec->data.array_data.num_elem * esize;
11908 }
11909 case MONO_NATIVE_BYVALARRAY: {
11910 // FIXME: Have to consider ArraySubType
11911 int esize;
11912 klass = mono_class_from_mono_type (type);
11913 if (klass->element_class == mono_defaults.char_class) {
11914 esize = unicode ? 2 : 1;
11915 *align = esize;
11916 } else {
11917 esize = mono_class_native_size (klass->element_class, align);
11918 }
11919 g_assert (mspec);
11920 return mspec->data.array_data.num_elem * esize;
11921 }
11922 case MONO_NATIVE_CUSTOM:
11923 *align = sizeof (gpointer);
11924 return sizeof (gpointer);
11925 break;
11926 case MONO_NATIVE_CURRENCY:
11927 case MONO_NATIVE_VBBYREFSTR:
11928 default:
11929 g_error ("native type %02x not implemented", native_type);
11930 break;
11931 }
11932 g_assert_not_reached ();
11933 return 0;
11934 }
11935
11936 /**
11937 * mono_marshal_asany:
11938 * This is a JIT icall, it sets the pending exception and returns NULL on error.
11939 */
11940 gpointer
mono_marshal_asany(MonoObject * o,MonoMarshalNative string_encoding,int param_attrs)11941 mono_marshal_asany (MonoObject *o, MonoMarshalNative string_encoding, int param_attrs)
11942 {
11943 MonoError error;
11944 MonoType *t;
11945 MonoClass *klass;
11946
11947 if (o == NULL)
11948 return NULL;
11949
11950 t = &o->vtable->klass->byval_arg;
11951 switch (t->type) {
11952 case MONO_TYPE_I4:
11953 case MONO_TYPE_U4:
11954 case MONO_TYPE_PTR:
11955 case MONO_TYPE_I1:
11956 case MONO_TYPE_U1:
11957 case MONO_TYPE_BOOLEAN:
11958 case MONO_TYPE_I2:
11959 case MONO_TYPE_U2:
11960 case MONO_TYPE_CHAR:
11961 case MONO_TYPE_I8:
11962 case MONO_TYPE_U8:
11963 case MONO_TYPE_R4:
11964 case MONO_TYPE_R8:
11965 return mono_object_unbox (o);
11966 break;
11967 case MONO_TYPE_STRING:
11968 switch (string_encoding) {
11969 case MONO_NATIVE_LPWSTR:
11970 return mono_marshal_string_to_utf16_copy ((MonoString*)o);
11971 case MONO_NATIVE_LPSTR:
11972 case MONO_NATIVE_UTF8STR:
11973 // Same code path, because in Mono, we treated strings as Utf8
11974 return mono_string_to_utf8str ((MonoString*)o);
11975 default:
11976 g_warning ("marshaling conversion %d not implemented", string_encoding);
11977 g_assert_not_reached ();
11978 }
11979 break;
11980 case MONO_TYPE_CLASS:
11981 case MONO_TYPE_VALUETYPE: {
11982 MonoMethod *method;
11983 gpointer pa [3];
11984 gpointer res;
11985 MonoBoolean delete_old = FALSE;
11986
11987 klass = t->data.klass;
11988
11989 if (mono_class_is_auto_layout (klass))
11990 break;
11991
11992 if (klass->valuetype && (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype))
11993 return mono_object_unbox (o);
11994
11995 res = mono_marshal_alloc (mono_class_native_size (klass, NULL), &error);
11996 if (!mono_error_ok (&error)) {
11997 mono_error_set_pending_exception (&error);
11998 return NULL;
11999 }
12000
12001 if (!((param_attrs & PARAM_ATTRIBUTE_OUT) && !(param_attrs & PARAM_ATTRIBUTE_IN))) {
12002 method = mono_marshal_get_struct_to_ptr (o->vtable->klass);
12003
12004 pa [0] = o;
12005 pa [1] = &res;
12006 pa [2] = &delete_old;
12007
12008 mono_runtime_invoke_checked (method, NULL, pa, &error);
12009 if (!mono_error_ok (&error)) {
12010 mono_error_set_pending_exception (&error);
12011 return NULL;
12012 }
12013 }
12014
12015 return res;
12016 }
12017 default:
12018 break;
12019 }
12020 mono_set_pending_exception (mono_get_exception_argument ("", "No PInvoke conversion exists for value passed to Object-typed parameter."));
12021 return NULL;
12022 }
12023
12024 /**
12025 * mono_marshal_free_asany:
12026 * This is a JIT icall, it sets the pending exception
12027 */
12028 void
mono_marshal_free_asany(MonoObject * o,gpointer ptr,MonoMarshalNative string_encoding,int param_attrs)12029 mono_marshal_free_asany (MonoObject *o, gpointer ptr, MonoMarshalNative string_encoding, int param_attrs)
12030 {
12031 MonoError error;
12032 MonoType *t;
12033 MonoClass *klass;
12034
12035 if (o == NULL)
12036 return;
12037
12038 t = &o->vtable->klass->byval_arg;
12039 switch (t->type) {
12040 case MONO_TYPE_STRING:
12041 switch (string_encoding) {
12042 case MONO_NATIVE_LPWSTR:
12043 case MONO_NATIVE_LPSTR:
12044 case MONO_NATIVE_UTF8STR:
12045 mono_marshal_free (ptr);
12046 break;
12047 default:
12048 g_warning ("marshaling conversion %d not implemented", string_encoding);
12049 g_assert_not_reached ();
12050 }
12051 break;
12052 case MONO_TYPE_CLASS:
12053 case MONO_TYPE_VALUETYPE: {
12054 klass = t->data.klass;
12055
12056 if (klass->valuetype && (mono_class_is_explicit_layout (klass) || klass->blittable || klass->enumtype))
12057 break;
12058
12059 if (param_attrs & PARAM_ATTRIBUTE_OUT) {
12060 MonoMethod *method = mono_marshal_get_ptr_to_struct (o->vtable->klass);
12061 gpointer pa [2];
12062
12063 pa [0] = &ptr;
12064 pa [1] = o;
12065
12066 mono_runtime_invoke_checked (method, NULL, pa, &error);
12067 if (!mono_error_ok (&error)) {
12068 mono_error_set_pending_exception (&error);
12069 return;
12070 }
12071 }
12072
12073 if (!((param_attrs & PARAM_ATTRIBUTE_OUT) && !(param_attrs & PARAM_ATTRIBUTE_IN))) {
12074 mono_struct_delete_old (klass, (char *)ptr);
12075 }
12076
12077 mono_marshal_free (ptr);
12078 break;
12079 }
12080 default:
12081 break;
12082 }
12083 }
12084
12085 /*
12086 * mono_marshal_get_generic_array_helper:
12087 *
12088 * Return a wrapper which is used to implement the implicit interfaces on arrays.
12089 * The wrapper routes calls to METHOD, which is one of the InternalArray_ methods in Array.
12090 */
12091 MonoMethod *
mono_marshal_get_generic_array_helper(MonoClass * klass,gchar * name,MonoMethod * method)12092 mono_marshal_get_generic_array_helper (MonoClass *klass, gchar *name, MonoMethod *method)
12093 {
12094 MonoMethodSignature *sig, *csig;
12095 MonoMethodBuilder *mb;
12096 MonoMethod *res;
12097 WrapperInfo *info;
12098 int i;
12099
12100 mb = mono_mb_new_no_dup_name (klass, name, MONO_WRAPPER_MANAGED_TO_MANAGED);
12101 mb->method->slot = -1;
12102
12103 mb->method->flags = METHOD_ATTRIBUTE_PRIVATE | METHOD_ATTRIBUTE_VIRTUAL |
12104 METHOD_ATTRIBUTE_NEW_SLOT | METHOD_ATTRIBUTE_HIDE_BY_SIG | METHOD_ATTRIBUTE_FINAL;
12105
12106 sig = mono_method_signature (method);
12107 csig = mono_metadata_signature_dup_full (method->klass->image, sig);
12108 csig->generic_param_count = 0;
12109
12110 #ifdef ENABLE_ILGEN
12111 mono_mb_emit_ldarg (mb, 0);
12112 for (i = 0; i < csig->param_count; i++)
12113 mono_mb_emit_ldarg (mb, i + 1);
12114 mono_mb_emit_managed_call (mb, method, NULL);
12115 mono_mb_emit_byte (mb, CEE_RET);
12116
12117 /* We can corlib internal methods */
12118 mb->skip_visibility = TRUE;
12119 #endif
12120 info = mono_wrapper_info_create (mb, WRAPPER_SUBTYPE_GENERIC_ARRAY_HELPER);
12121 info->d.generic_array_helper.method = method;
12122 res = mono_mb_create (mb, csig, csig->param_count + 16, info);
12123
12124 mono_mb_free (mb);
12125
12126 return res;
12127 }
12128
12129 /*
12130 * The mono_win32_compat_* functions are implementations of inline
12131 * Windows kernel32 APIs, which are DllImport-able under MS.NET,
12132 * although not exported by kernel32.
12133 *
12134 * We map the appropiate kernel32 entries to these functions using
12135 * dllmaps declared in the global etc/mono/config.
12136 */
12137
12138 void
mono_win32_compat_CopyMemory(gpointer dest,gconstpointer source,gsize length)12139 mono_win32_compat_CopyMemory (gpointer dest, gconstpointer source, gsize length)
12140 {
12141 if (!dest || !source)
12142 return;
12143
12144 memcpy (dest, source, length);
12145 }
12146
12147 void
mono_win32_compat_FillMemory(gpointer dest,gsize length,guchar fill)12148 mono_win32_compat_FillMemory (gpointer dest, gsize length, guchar fill)
12149 {
12150 memset (dest, fill, length);
12151 }
12152
12153 void
mono_win32_compat_MoveMemory(gpointer dest,gconstpointer source,gsize length)12154 mono_win32_compat_MoveMemory (gpointer dest, gconstpointer source, gsize length)
12155 {
12156 if (!dest || !source)
12157 return;
12158
12159 memmove (dest, source, length);
12160 }
12161
12162 void
mono_win32_compat_ZeroMemory(gpointer dest,gsize length)12163 mono_win32_compat_ZeroMemory (gpointer dest, gsize length)
12164 {
12165 memset (dest, 0, length);
12166 }
12167
12168 void
mono_marshal_find_nonzero_bit_offset(guint8 * buf,int len,int * byte_offset,guint8 * bitmask)12169 mono_marshal_find_nonzero_bit_offset (guint8 *buf, int len, int *byte_offset, guint8 *bitmask)
12170 {
12171 int i;
12172 guint8 byte;
12173
12174 for (i = 0; i < len; ++i)
12175 if (buf [i])
12176 break;
12177
12178 g_assert (i < len);
12179
12180 byte = buf [i];
12181 while (byte && !(byte & 1))
12182 byte >>= 1;
12183 g_assert (byte == 1);
12184
12185 *byte_offset = i;
12186 *bitmask = buf [i];
12187 }
12188
12189 MonoMethod *
mono_marshal_get_thunk_invoke_wrapper(MonoMethod * method)12190 mono_marshal_get_thunk_invoke_wrapper (MonoMethod *method)
12191 {
12192 MonoMethodBuilder *mb;
12193 MonoMethodSignature *sig, *csig;
12194 MonoExceptionClause *clause;
12195 MonoImage *image;
12196 MonoClass *klass;
12197 GHashTable *cache;
12198 MonoMethod *res;
12199 int i, param_count, sig_size, pos_leave;
12200
12201 g_assert (method);
12202
12203 // FIXME: we need to store the exception into a MonoHandle
12204 g_assert (!mono_threads_is_coop_enabled ());
12205
12206 klass = method->klass;
12207 image = method->klass->image;
12208
12209 cache = get_cache (&mono_method_get_wrapper_cache (method)->thunk_invoke_cache, mono_aligned_addr_hash, NULL);
12210
12211 if ((res = mono_marshal_find_in_cache (cache, method)))
12212 return res;
12213
12214 sig = mono_method_signature (method);
12215 mb = mono_mb_new (klass, method->name, MONO_WRAPPER_NATIVE_TO_MANAGED);
12216
12217 /* add "this" and exception param */
12218 param_count = sig->param_count + sig->hasthis + 1;
12219
12220 /* dup & extend signature */
12221 csig = mono_metadata_signature_alloc (image, param_count);
12222 sig_size = MONO_SIZEOF_METHOD_SIGNATURE + sig->param_count * sizeof (MonoType *);
12223 memcpy (csig, sig, sig_size);
12224 csig->param_count = param_count;
12225 csig->hasthis = 0;
12226 csig->pinvoke = 1;
12227 csig->call_convention = MONO_CALL_DEFAULT;
12228
12229 if (sig->hasthis) {
12230 /* add "this" */
12231 csig->params [0] = &klass->byval_arg;
12232 /* move params up by one */
12233 for (i = 0; i < sig->param_count; i++)
12234 csig->params [i + 1] = sig->params [i];
12235 }
12236
12237 /* setup exception param as byref+[out] */
12238 csig->params [param_count - 1] = mono_metadata_type_dup (image,
12239 &mono_defaults.exception_class->byval_arg);
12240 csig->params [param_count - 1]->byref = 1;
12241 csig->params [param_count - 1]->attrs = PARAM_ATTRIBUTE_OUT;
12242
12243 /* convert struct return to object */
12244 if (MONO_TYPE_ISSTRUCT (sig->ret))
12245 csig->ret = &mono_defaults.object_class->byval_arg;
12246
12247 #ifdef ENABLE_ILGEN
12248 /* local 0 (temp for exception object) */
12249 mono_mb_add_local (mb, &mono_defaults.object_class->byval_arg);
12250
12251 /* local 1 (temp for result) */
12252 if (!MONO_TYPE_IS_VOID (sig->ret))
12253 mono_mb_add_local (mb, sig->ret);
12254
12255 /* clear exception arg */
12256 mono_mb_emit_ldarg (mb, param_count - 1);
12257 mono_mb_emit_byte (mb, CEE_LDNULL);
12258 mono_mb_emit_byte (mb, CEE_STIND_REF);
12259
12260 /* try */
12261 clause = (MonoExceptionClause *)mono_image_alloc0 (image, sizeof (MonoExceptionClause));
12262 clause->try_offset = mono_mb_get_label (mb);
12263
12264 /* push method's args */
12265 for (i = 0; i < param_count - 1; i++) {
12266 MonoType *type;
12267 MonoClass *klass;
12268
12269 mono_mb_emit_ldarg (mb, i);
12270
12271 /* get the byval type of the param */
12272 klass = mono_class_from_mono_type (csig->params [i]);
12273 type = &klass->byval_arg;
12274
12275 /* unbox struct args */
12276 if (MONO_TYPE_ISSTRUCT (type)) {
12277 mono_mb_emit_op (mb, CEE_UNBOX, klass);
12278
12279 /* byref args & and the "this" arg must remain a ptr.
12280 Otherwise make a copy of the value type */
12281 if (!(csig->params [i]->byref || (i == 0 && sig->hasthis)))
12282 mono_mb_emit_op (mb, CEE_LDOBJ, klass);
12283
12284 csig->params [i] = &mono_defaults.object_class->byval_arg;
12285 }
12286 }
12287
12288 /* call */
12289 if (method->flags & METHOD_ATTRIBUTE_VIRTUAL)
12290 mono_mb_emit_op (mb, CEE_CALLVIRT, method);
12291 else
12292 mono_mb_emit_op (mb, CEE_CALL, method);
12293
12294 /* save result at local 1 */
12295 if (!MONO_TYPE_IS_VOID (sig->ret))
12296 mono_mb_emit_stloc (mb, 1);
12297
12298 pos_leave = mono_mb_emit_branch (mb, CEE_LEAVE);
12299
12300 /* catch */
12301 clause->flags = MONO_EXCEPTION_CLAUSE_NONE;
12302 clause->try_len = mono_mb_get_pos (mb) - clause->try_offset;
12303 clause->data.catch_class = mono_defaults.object_class;
12304
12305 clause->handler_offset = mono_mb_get_label (mb);
12306
12307 /* store exception at local 0 */
12308 mono_mb_emit_stloc (mb, 0);
12309 mono_mb_emit_ldarg (mb, param_count - 1);
12310 mono_mb_emit_ldloc (mb, 0);
12311 mono_mb_emit_byte (mb, CEE_STIND_REF);
12312 mono_mb_emit_branch (mb, CEE_LEAVE);
12313
12314 clause->handler_len = mono_mb_get_pos (mb) - clause->handler_offset;
12315
12316 mono_mb_set_clauses (mb, 1, clause);
12317
12318 mono_mb_patch_branch (mb, pos_leave);
12319 /* end-try */
12320
12321 if (!MONO_TYPE_IS_VOID (sig->ret)) {
12322 mono_mb_emit_ldloc (mb, 1);
12323
12324 /* box the return value */
12325 if (MONO_TYPE_ISSTRUCT (sig->ret))
12326 mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type (sig->ret));
12327 }
12328
12329 mono_mb_emit_byte (mb, CEE_RET);
12330 #endif
12331
12332 res = mono_mb_create_and_cache (cache, method, mb, csig, param_count + 16);
12333 mono_mb_free (mb);
12334
12335 return res;
12336 }
12337
12338 /*
12339 * mono_marshal_free_dynamic_wrappers:
12340 *
12341 * Free wrappers of the dynamic method METHOD.
12342 */
12343 void
mono_marshal_free_dynamic_wrappers(MonoMethod * method)12344 mono_marshal_free_dynamic_wrappers (MonoMethod *method)
12345 {
12346 MonoImage *image = method->klass->image;
12347
12348 g_assert (method_is_dynamic (method));
12349
12350 /* This could be called during shutdown */
12351 if (marshal_mutex_initialized)
12352 mono_marshal_lock ();
12353 /*
12354 * FIXME: We currently leak the wrappers. Freeing them would be tricky as
12355 * they could be shared with other methods ?
12356 */
12357 if (image->wrapper_caches.runtime_invoke_direct_cache)
12358 g_hash_table_remove (image->wrapper_caches.runtime_invoke_direct_cache, method);
12359 if (image->wrapper_caches.delegate_abstract_invoke_cache)
12360 g_hash_table_foreach_remove (image->wrapper_caches.delegate_abstract_invoke_cache, signature_pointer_pair_matches_pointer, method);
12361 // FIXME: Need to clear the caches in other images as well
12362 if (image->delegate_bound_static_invoke_cache)
12363 g_hash_table_remove (image->delegate_bound_static_invoke_cache, mono_method_signature (method));
12364
12365 if (marshal_mutex_initialized)
12366 mono_marshal_unlock ();
12367 }
12368
12369 static void
mono_marshal_ftnptr_eh_callback(guint32 gchandle)12370 mono_marshal_ftnptr_eh_callback (guint32 gchandle)
12371 {
12372 g_assert (ftnptr_eh_callback);
12373 ftnptr_eh_callback (gchandle);
12374 }
12375
12376 static void
ftnptr_eh_callback_default(guint32 gchandle)12377 ftnptr_eh_callback_default (guint32 gchandle)
12378 {
12379 MonoException *exc;
12380 gpointer stackdata;
12381
12382 mono_threads_enter_gc_unsafe_region_unbalanced (&stackdata);
12383
12384 exc = (MonoException*) mono_gchandle_get_target (gchandle);
12385
12386 mono_gchandle_free (gchandle);
12387
12388 mono_reraise_exception_deprecated (exc);
12389 }
12390
12391 /*
12392 * mono_install_ftnptr_eh_callback:
12393 *
12394 * Install a callback that should be called when there is a managed exception
12395 * in a native-to-managed wrapper. This is mainly used by iOS to convert a
12396 * managed exception to a native exception, to properly unwind the native
12397 * stack; this native exception will then be converted back to a managed
12398 * exception in their managed-to-native wrapper.
12399 */
12400 void
mono_install_ftnptr_eh_callback(MonoFtnPtrEHCallback callback)12401 mono_install_ftnptr_eh_callback (MonoFtnPtrEHCallback callback)
12402 {
12403 ftnptr_eh_callback = callback;
12404 }
12405
12406 static MonoThreadInfo*
mono_icall_start(HandleStackMark * stackmark,MonoError * error)12407 mono_icall_start (HandleStackMark *stackmark, MonoError *error)
12408 {
12409 MonoThreadInfo *info = mono_thread_info_current ();
12410
12411 mono_stack_mark_init (info, stackmark);
12412 error_init (error);
12413 return info;
12414 }
12415
12416 static void
mono_icall_end(MonoThreadInfo * info,HandleStackMark * stackmark,MonoError * error)12417 mono_icall_end (MonoThreadInfo *info, HandleStackMark *stackmark, MonoError *error)
12418 {
12419 mono_stack_mark_pop (info, stackmark);
12420 if (G_UNLIKELY (!is_ok (error)))
12421 mono_error_set_pending_exception (error);
12422 }
12423
12424 static MonoObjectHandle
mono_icall_handle_new(gpointer rawobj)12425 mono_icall_handle_new (gpointer rawobj)
12426 {
12427 #ifdef MONO_HANDLE_TRACK_OWNER
12428 return mono_handle_new (rawobj, "<marshal args>");
12429 #else
12430 return mono_handle_new (rawobj);
12431 #endif
12432 }
12433
12434 static MonoObjectHandle
mono_icall_handle_new_interior(gpointer rawobj)12435 mono_icall_handle_new_interior (gpointer rawobj)
12436 {
12437 #ifdef MONO_HANDLE_TRACK_OWNER
12438 return mono_handle_new_interior (rawobj, "<marshal args>");
12439 #else
12440 return mono_handle_new_interior (rawobj);
12441 #endif
12442 }
12443