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