1 /**
2  * \file
3  * Object creation for the Mono runtime
4  *
5  * Author:
6  *   Miguel de Icaza (miguel@ximian.com)
7  *   Paolo Molaro (lupus@ximian.com)
8  *
9  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10  * Copyright 2004-2011 Novell, Inc (http://www.novell.com)
11  * Copyright 2001 Xamarin Inc (http://www.xamarin.com)
12  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
13  */
14 #include <config.h>
15 #ifdef HAVE_ALLOCA_H
16 #include <alloca.h>
17 #endif
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <mono/metadata/mono-endian.h>
22 #include <mono/metadata/tabledefs.h>
23 #include <mono/metadata/tokentype.h>
24 #include <mono/metadata/loader.h>
25 #include <mono/metadata/object.h>
26 #include <mono/metadata/gc-internals.h>
27 #include <mono/metadata/exception.h>
28 #include <mono/metadata/exception-internals.h>
29 #include <mono/metadata/domain-internals.h>
30 #include "mono/metadata/metadata-internals.h"
31 #include "mono/metadata/class-internals.h"
32 #include <mono/metadata/assembly.h>
33 #include <mono/metadata/marshal.h>
34 #include "mono/metadata/debug-helpers.h"
35 #include <mono/metadata/threads.h>
36 #include <mono/metadata/threads-types.h>
37 #include <mono/metadata/environment.h>
38 #include "mono/metadata/profiler-private.h"
39 #include "mono/metadata/security-manager.h"
40 #include <mono/metadata/verify-internals.h>
41 #include <mono/metadata/reflection-internals.h>
42 #include <mono/metadata/w32event.h>
43 #include <mono/metadata/custom-attrs-internals.h>
44 #include <mono/utils/strenc.h>
45 #include <mono/utils/mono-counters.h>
46 #include <mono/utils/mono-error-internals.h>
47 #include <mono/utils/mono-memory-model.h>
48 #include <mono/utils/checked-build.h>
49 #include <mono/utils/mono-threads.h>
50 #include <mono/utils/mono-threads-coop.h>
51 #include <mono/utils/mono-logger-internals.h>
52 #include "cominterop.h"
53 #include <mono/utils/w32api.h>
54 #include <mono/utils/unlocked.h>
55 
56 static void
57 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error);
58 
59 static MonoString*
60 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error);
61 
62 static void
63 free_main_args (void);
64 
65 static char *
66 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error);
67 
68 static void
69 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size);
70 
71 static MonoMethod*
72 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error);
73 
74 /* Class lazy loading functions */
75 static GENERATE_GET_CLASS_WITH_CACHE (pointer, "System.Reflection", "Pointer")
76 static GENERATE_GET_CLASS_WITH_CACHE (remoting_services, "System.Runtime.Remoting", "RemotingServices")
77 static GENERATE_GET_CLASS_WITH_CACHE (unhandled_exception_event_args, "System", "UnhandledExceptionEventArgs")
78 static GENERATE_GET_CLASS_WITH_CACHE (sta_thread_attribute, "System", "STAThreadAttribute")
79 static GENERATE_GET_CLASS_WITH_CACHE (activation_services, "System.Runtime.Remoting.Activation", "ActivationServices")
80 
81 
82 #define ldstr_lock() mono_os_mutex_lock (&ldstr_section)
83 #define ldstr_unlock() mono_os_mutex_unlock (&ldstr_section)
84 static mono_mutex_t ldstr_section;
85 
86 
87 /**
88  * mono_runtime_object_init:
89  * \param this_obj the object to initialize
90  * This function calls the zero-argument constructor (which must
91  * exist) for the given object.
92  */
93 void
mono_runtime_object_init(MonoObject * this_obj)94 mono_runtime_object_init (MonoObject *this_obj)
95 {
96 	MonoError error;
97 	mono_runtime_object_init_checked (this_obj, &error);
98 	mono_error_assert_ok (&error);
99 }
100 
101 /**
102  * mono_runtime_object_init_checked:
103  * \param this_obj the object to initialize
104  * \param error set on error.
105  * This function calls the zero-argument constructor (which must
106  * exist) for the given object and returns TRUE on success, or FALSE
107  * on error and sets \p error.
108  */
109 gboolean
mono_runtime_object_init_checked(MonoObject * this_obj,MonoError * error)110 mono_runtime_object_init_checked (MonoObject *this_obj, MonoError *error)
111 {
112 	MONO_REQ_GC_UNSAFE_MODE;
113 
114 	MonoMethod *method = NULL;
115 	MonoClass *klass = this_obj->vtable->klass;
116 
117 	error_init (error);
118 	method = mono_class_get_method_from_name (klass, ".ctor", 0);
119 	if (!method)
120 		g_error ("Could not lookup zero argument constructor for class %s", mono_type_get_full_name (klass));
121 
122 	if (method->klass->valuetype)
123 		this_obj = (MonoObject *)mono_object_unbox (this_obj);
124 
125 	mono_runtime_invoke_checked (method, this_obj, NULL, error);
126 	return is_ok (error);
127 }
128 
129 /* The pseudo algorithm for type initialization from the spec
130 Note it doesn't say anything about domains - only threads.
131 
132 2. If the type is initialized you are done.
133 2.1. If the type is not yet initialized, try to take an
134      initialization lock.
135 2.2. If successful, record this thread as responsible for
136      initializing the type and proceed to step 2.3.
137 2.2.1. If not, see whether this thread or any thread
138      waiting for this thread to complete already holds the lock.
139 2.2.2. If so, return since blocking would create a deadlock.  This thread
140      will now see an incompletely initialized state for the type,
141      but no deadlock will arise.
142 2.2.3  If not, block until the type is initialized then return.
143 2.3 Initialize the parent type and then all interfaces implemented
144     by this type.
145 2.4 Execute the type initialization code for this type.
146 2.5 Mark the type as initialized, release the initialization lock,
147     awaken any threads waiting for this type to be initialized,
148     and return.
149 
150 */
151 
152 typedef struct
153 {
154 	MonoNativeThreadId initializing_tid;
155 	guint32 waiting_count;
156 	gboolean done;
157 	MonoCoopMutex mutex;
158 	/* condvar used to wait for 'done' becoming TRUE */
159 	MonoCoopCond cond;
160 } TypeInitializationLock;
161 
162 /* for locking access to type_initialization_hash and blocked_thread_hash */
163 static MonoCoopMutex type_initialization_section;
164 
165 static inline void
mono_type_initialization_lock(void)166 mono_type_initialization_lock (void)
167 {
168 	/* The critical sections protected by this lock in mono_runtime_class_init_full () can block */
169 	mono_coop_mutex_lock (&type_initialization_section);
170 }
171 
172 static inline void
mono_type_initialization_unlock(void)173 mono_type_initialization_unlock (void)
174 {
175 	mono_coop_mutex_unlock (&type_initialization_section);
176 }
177 
178 static void
mono_type_init_lock(TypeInitializationLock * lock)179 mono_type_init_lock (TypeInitializationLock *lock)
180 {
181 	MONO_REQ_GC_NEUTRAL_MODE;
182 
183 	mono_coop_mutex_lock (&lock->mutex);
184 }
185 
186 static void
mono_type_init_unlock(TypeInitializationLock * lock)187 mono_type_init_unlock (TypeInitializationLock *lock)
188 {
189 	mono_coop_mutex_unlock (&lock->mutex);
190 }
191 
192 /* from vtable to lock */
193 static GHashTable *type_initialization_hash;
194 
195 /* from thread id to thread id being waited on */
196 static GHashTable *blocked_thread_hash;
197 
198 /* Main thread */
199 static MonoThread *main_thread;
200 
201 /* Functions supplied by the runtime */
202 static MonoRuntimeCallbacks callbacks;
203 
204 /**
205  * mono_thread_set_main:
206  * \param thread thread to set as the main thread
207  * This function can be used to instruct the runtime to treat \p thread
208  * as the main thread, ie, the thread that would normally execute the \c Main
209  * method. This basically means that at the end of \p thread, the runtime will
210  * wait for the existing foreground threads to quit and other such details.
211  */
212 void
mono_thread_set_main(MonoThread * thread)213 mono_thread_set_main (MonoThread *thread)
214 {
215 	MONO_REQ_GC_UNSAFE_MODE;
216 
217 	static gboolean registered = FALSE;
218 
219 	if (!registered) {
220 		MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object");
221 		registered = TRUE;
222 	}
223 
224 	main_thread = thread;
225 }
226 
227 /**
228  * mono_thread_get_main:
229  */
230 MonoThread*
mono_thread_get_main(void)231 mono_thread_get_main (void)
232 {
233 	MONO_REQ_GC_UNSAFE_MODE;
234 
235 	return main_thread;
236 }
237 
238 void
mono_type_initialization_init(void)239 mono_type_initialization_init (void)
240 {
241 	mono_coop_mutex_init_recursive (&type_initialization_section);
242 	type_initialization_hash = g_hash_table_new (NULL, NULL);
243 	blocked_thread_hash = g_hash_table_new (NULL, NULL);
244 	mono_os_mutex_init_recursive (&ldstr_section);
245 	mono_register_jit_icall (ves_icall_string_alloc, "ves_icall_string_alloc", mono_create_icall_signature ("object int"), FALSE);
246 }
247 
248 void
mono_type_initialization_cleanup(void)249 mono_type_initialization_cleanup (void)
250 {
251 #if 0
252 	/* This is causing race conditions with
253 	 * mono_release_type_locks
254 	 */
255 	mono_coop_mutex_destroy (&type_initialization_section);
256 	g_hash_table_destroy (type_initialization_hash);
257 	type_initialization_hash = NULL;
258 #endif
259 	mono_os_mutex_destroy (&ldstr_section);
260 	g_hash_table_destroy (blocked_thread_hash);
261 	blocked_thread_hash = NULL;
262 
263 	free_main_args ();
264 }
265 
266 /**
267  * get_type_init_exception_for_vtable:
268  *
269  *   Return the stored type initialization exception for VTABLE.
270  */
271 static MonoException*
get_type_init_exception_for_vtable(MonoVTable * vtable)272 get_type_init_exception_for_vtable (MonoVTable *vtable)
273 {
274 	MONO_REQ_GC_UNSAFE_MODE;
275 
276 	MonoError error;
277 	MonoDomain *domain = vtable->domain;
278 	MonoClass *klass = vtable->klass;
279 	MonoException *ex;
280 	gchar *full_name;
281 
282 	if (!vtable->init_failed)
283 		g_error ("Trying to get the init exception for a non-failed vtable of class %s", mono_type_get_full_name (klass));
284 
285 	/*
286 	 * If the initializing thread was rudely aborted, the exception is not stored
287 	 * in the hash.
288 	 */
289 	ex = NULL;
290 	mono_domain_lock (domain);
291 	if (domain->type_init_exception_hash)
292 		ex = (MonoException *)mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
293 	mono_domain_unlock (domain);
294 
295 	if (!ex) {
296 		if (klass->name_space && *klass->name_space)
297 			full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
298 		else
299 			full_name = g_strdup (klass->name);
300 		ex = mono_get_exception_type_initialization_checked (full_name, NULL, &error);
301 		g_free (full_name);
302 		return_val_if_nok (&error, NULL);
303 	}
304 
305 	return ex;
306 }
307 
308 /**
309  * mono_runtime_class_init:
310  * \param vtable vtable that needs to be initialized
311  * This routine calls the class constructor for \p vtable.
312  */
313 void
mono_runtime_class_init(MonoVTable * vtable)314 mono_runtime_class_init (MonoVTable *vtable)
315 {
316 	MONO_REQ_GC_UNSAFE_MODE;
317 	MonoError error;
318 
319 	mono_runtime_class_init_full (vtable, &error);
320 	mono_error_assert_ok (&error);
321 }
322 
323 /*
324  * Returns TRUE if the lock was freed.
325  * LOCKING: Caller should hold type_initialization_lock.
326  */
327 static gboolean
unref_type_lock(TypeInitializationLock * lock)328 unref_type_lock (TypeInitializationLock *lock)
329 {
330 	--lock->waiting_count;
331 	if (lock->waiting_count == 0) {
332 		mono_coop_mutex_destroy (&lock->mutex);
333 		mono_coop_cond_destroy (&lock->cond);
334 		g_free (lock);
335 		return TRUE;
336 	} else {
337 		return FALSE;
338 	}
339 }
340 
341 /**
342  * mono_runtime_class_init_full:
343  * \param vtable that neeeds to be initialized
344  * \param error set on error
345  * \returns TRUE if class constructor \c .cctor has been initialized successfully, or FALSE otherwise and sets \p error.
346  */
347 gboolean
mono_runtime_class_init_full(MonoVTable * vtable,MonoError * error)348 mono_runtime_class_init_full (MonoVTable *vtable, MonoError *error)
349 {
350 	MONO_REQ_GC_UNSAFE_MODE;
351 
352 	MonoMethod *method = NULL;
353 	MonoClass *klass;
354 	gchar *full_name;
355 	MonoDomain *domain = vtable->domain;
356 	TypeInitializationLock *lock;
357 	MonoNativeThreadId tid;
358 	int do_initialization = 0;
359 	MonoDomain *last_domain = NULL;
360 	gboolean pending_tae = FALSE;
361 
362 	error_init (error);
363 
364 	if (vtable->initialized)
365 		return TRUE;
366 
367 	klass = vtable->klass;
368 
369 	if (!klass->image->checked_module_cctor) {
370 		mono_image_check_for_module_cctor (klass->image);
371 		if (klass->image->has_module_cctor) {
372 			MonoClass *module_klass;
373 			MonoVTable *module_vtable;
374 
375 			module_klass = mono_class_get_checked (klass->image, MONO_TOKEN_TYPE_DEF | 1, error);
376 			if (!module_klass) {
377 				return FALSE;
378 			}
379 
380 			module_vtable = mono_class_vtable_full (vtable->domain, module_klass, error);
381 			if (!module_vtable)
382 				return FALSE;
383 			if (!mono_runtime_class_init_full (module_vtable, error))
384 				return FALSE;
385 		}
386 	}
387 	method = mono_class_get_cctor (klass);
388 	if (!method) {
389 		vtable->initialized = 1;
390 		return TRUE;
391 	}
392 
393 	tid = mono_native_thread_id_get ();
394 
395 	/*
396 	 * Due some preprocessing inside a global lock. If we are the first thread
397 	 * trying to initialize this class, create a separate lock+cond var, and
398 	 * acquire it before leaving the global lock. The other threads will wait
399 	 * on this cond var.
400 	 */
401 
402 	mono_type_initialization_lock ();
403 	/* double check... */
404 	if (vtable->initialized) {
405 		mono_type_initialization_unlock ();
406 		return TRUE;
407 	}
408 	if (vtable->init_failed) {
409 		mono_type_initialization_unlock ();
410 
411 		/* The type initialization already failed once, rethrow the same exception */
412 		mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
413 		return FALSE;
414 	}
415 	lock = (TypeInitializationLock *)g_hash_table_lookup (type_initialization_hash, vtable);
416 	if (lock == NULL) {
417 		/* This thread will get to do the initialization */
418 		if (mono_domain_get () != domain) {
419 			/* Transfer into the target domain */
420 			last_domain = mono_domain_get ();
421 			if (!mono_domain_set (domain, FALSE)) {
422 				vtable->initialized = 1;
423 				mono_type_initialization_unlock ();
424 				mono_error_set_exception_instance (error, mono_get_exception_appdomain_unloaded ());
425 				return FALSE;
426 			}
427 		}
428 		lock = (TypeInitializationLock *)g_malloc0 (sizeof (TypeInitializationLock));
429 		mono_coop_mutex_init_recursive (&lock->mutex);
430 		mono_coop_cond_init (&lock->cond);
431 		lock->initializing_tid = tid;
432 		lock->waiting_count = 1;
433 		lock->done = FALSE;
434 		g_hash_table_insert (type_initialization_hash, vtable, lock);
435 		do_initialization = 1;
436 	} else {
437 		gpointer blocked;
438 		TypeInitializationLock *pending_lock;
439 
440 		if (mono_native_thread_id_equals (lock->initializing_tid, tid)) {
441 			mono_type_initialization_unlock ();
442 			return TRUE;
443 		}
444 		/* see if the thread doing the initialization is already blocked on this thread */
445 		gboolean is_blocked = TRUE;
446 		blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (lock->initializing_tid));
447 		while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
448 			if (mono_native_thread_id_equals (pending_lock->initializing_tid, tid)) {
449 				if (!pending_lock->done) {
450 					mono_type_initialization_unlock ();
451 					return TRUE;
452 				} else {
453 					/* the thread doing the initialization is blocked on this thread,
454 					   but on a lock that has already been freed. It just hasn't got
455 					   time to awake */
456 					is_blocked = FALSE;
457 					break;
458 				}
459 			}
460 			blocked = GUINT_TO_POINTER (MONO_NATIVE_THREAD_ID_TO_UINT (pending_lock->initializing_tid));
461 		}
462 		++lock->waiting_count;
463 		/* record the fact that we are waiting on the initializing thread */
464 		if (is_blocked)
465 			g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
466 	}
467 	mono_type_initialization_unlock ();
468 
469 	if (do_initialization) {
470 		MonoException *exc = NULL;
471 
472 		/* We are holding the per-vtable lock, do the actual initialization */
473 
474 		mono_threads_begin_abort_protected_block ();
475 		mono_runtime_try_invoke (method, NULL, NULL, (MonoObject**) &exc, error);
476 		mono_threads_end_abort_protected_block ();
477 
478 		//exception extracted, error will be set to the right value later
479 		if (exc == NULL && !mono_error_ok (error))//invoking failed but exc was not set
480 			exc = mono_error_convert_to_exception (error);
481 		else
482 			mono_error_cleanup (error);
483 
484 		error_init (error);
485 
486 		/* If the initialization failed, mark the class as unusable. */
487 		/* Avoid infinite loops */
488 		if (!(!exc ||
489 			  (klass->image == mono_defaults.corlib &&
490 			   !strcmp (klass->name_space, "System") &&
491 			   !strcmp (klass->name, "TypeInitializationException")))) {
492 			vtable->init_failed = 1;
493 
494 			if (klass->name_space && *klass->name_space)
495 				full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
496 			else
497 				full_name = g_strdup (klass->name);
498 
499 			MonoException *exc_to_throw = mono_get_exception_type_initialization_checked (full_name, exc, error);
500 			g_free (full_name);
501 
502 			mono_error_assert_ok (error); //We can't recover from this, no way to fail a type we can't alloc a failure.
503 
504 			/*
505 			 * Store the exception object so it could be thrown on subsequent
506 			 * accesses.
507 			 */
508 			mono_domain_lock (domain);
509 			if (!domain->type_init_exception_hash)
510 				domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "type initialization exceptions table");
511 			mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
512 			mono_domain_unlock (domain);
513 		}
514 
515 		if (last_domain)
516 			mono_domain_set (last_domain, TRUE);
517 
518 		/* Signal to the other threads that we are done */
519 		mono_type_init_lock (lock);
520 		lock->done = TRUE;
521 		mono_coop_cond_broadcast (&lock->cond);
522 		mono_type_init_unlock (lock);
523 
524 		/*
525 		 * This can happen if the cctor self-aborts. We need to reactivate tae
526 		 * (next interruption checkpoint will throw it) and make sure we won't
527 		 * throw tie for the type.
528 		 */
529 		if (exc && mono_object_class (exc) == mono_defaults.threadabortexception_class) {
530 			pending_tae = TRUE;
531 			mono_thread_resume_interruption (FALSE);
532 		}
533 	} else {
534 		/* this just blocks until the initializing thread is done */
535 		mono_type_init_lock (lock);
536 		while (!lock->done)
537 			mono_coop_cond_wait (&lock->cond, &lock->mutex);
538 		mono_type_init_unlock (lock);
539 	}
540 
541 	/* Do cleanup and setting vtable->initialized inside the global lock again */
542 	mono_type_initialization_lock ();
543 	if (!do_initialization)
544 		g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
545 	gboolean deleted = unref_type_lock (lock);
546 	if (deleted)
547 		g_hash_table_remove (type_initialization_hash, vtable);
548 	/* Have to set this here since we check it inside the global lock */
549 	if (do_initialization && !vtable->init_failed)
550 		vtable->initialized = 1;
551 	mono_type_initialization_unlock ();
552 
553 	/* If vtable init fails because of TAE, we don't throw TIE, only the TAE */
554 	if (vtable->init_failed && !pending_tae) {
555 		/* Either we were the initializing thread or we waited for the initialization */
556 		mono_error_set_exception_instance (error, get_type_init_exception_for_vtable (vtable));
557 		return FALSE;
558 	}
559 	return TRUE;
560 }
561 
562 static
release_type_locks(gpointer key,gpointer value,gpointer user)563 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
564 {
565 	MONO_REQ_GC_NEUTRAL_MODE;
566 
567 	MonoVTable *vtable = (MonoVTable*)key;
568 
569 	TypeInitializationLock *lock = (TypeInitializationLock*) value;
570 	if (mono_native_thread_id_equals (lock->initializing_tid, MONO_UINT_TO_NATIVE_THREAD_ID (GPOINTER_TO_UINT (user))) && !lock->done) {
571 		lock->done = TRUE;
572 		/*
573 		 * Have to set this since it cannot be set by the normal code in
574 		 * mono_runtime_class_init (). In this case, the exception object is not stored,
575 		 * and get_type_init_exception_for_class () needs to be aware of this.
576 		 */
577 		mono_type_init_lock (lock);
578 		vtable->init_failed = 1;
579 		mono_coop_cond_broadcast (&lock->cond);
580 		mono_type_init_unlock (lock);
581 		gboolean deleted = unref_type_lock (lock);
582 		if (deleted)
583 			return TRUE;
584 	}
585 	return FALSE;
586 }
587 
588 void
mono_release_type_locks(MonoInternalThread * thread)589 mono_release_type_locks (MonoInternalThread *thread)
590 {
591 	MONO_REQ_GC_UNSAFE_MODE;
592 
593 	mono_type_initialization_lock ();
594 	g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
595 	mono_type_initialization_unlock ();
596 }
597 
598 #ifndef DISABLE_REMOTING
599 
600 static gpointer
create_remoting_trampoline(MonoDomain * domain,MonoMethod * method,MonoRemotingTarget target,MonoError * error)601 create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
602 {
603 	if (!callbacks.create_remoting_trampoline)
604 		g_error ("remoting not installed");
605 	return callbacks.create_remoting_trampoline (domain, method, target, error);
606 }
607 
608 #endif
609 
610 static MonoImtTrampolineBuilder imt_trampoline_builder;
611 static gboolean always_build_imt_trampolines;
612 
613 #if (MONO_IMT_SIZE > 32)
614 #error "MONO_IMT_SIZE cannot be larger than 32"
615 #endif
616 
617 void
mono_install_callbacks(MonoRuntimeCallbacks * cbs)618 mono_install_callbacks (MonoRuntimeCallbacks *cbs)
619 {
620 	memcpy (&callbacks, cbs, sizeof (*cbs));
621 }
622 
623 MonoRuntimeCallbacks*
mono_get_runtime_callbacks(void)624 mono_get_runtime_callbacks (void)
625 {
626 	return &callbacks;
627 }
628 
629 void
mono_install_imt_trampoline_builder(MonoImtTrampolineBuilder func)630 mono_install_imt_trampoline_builder (MonoImtTrampolineBuilder func)
631 {
632 	imt_trampoline_builder = func;
633 }
634 
635 void
mono_set_always_build_imt_trampolines(gboolean value)636 mono_set_always_build_imt_trampolines (gboolean value)
637 {
638 	always_build_imt_trampolines = value;
639 }
640 
641 /**
642  * mono_compile_method:
643  * \param method The method to compile.
644  * This JIT-compiles the method, and returns the pointer to the native code
645  * produced.
646  */
647 gpointer
mono_compile_method(MonoMethod * method)648 mono_compile_method (MonoMethod *method)
649 {
650 	MonoError error;
651 	gpointer result = mono_compile_method_checked (method, &error);
652 	mono_error_cleanup (&error);
653 	return result;
654 }
655 
656 /**
657  * mono_compile_method_checked:
658  * \param method The method to compile.
659  * \param error set on error.
660  * This JIT-compiles the method, and returns the pointer to the native code
661  * produced.  On failure returns NULL and sets \p error.
662  */
663 gpointer
mono_compile_method_checked(MonoMethod * method,MonoError * error)664 mono_compile_method_checked (MonoMethod *method, MonoError *error)
665 {
666 	gpointer res;
667 
668 	MONO_REQ_GC_NEUTRAL_MODE
669 
670 	error_init (error);
671 
672 	g_assert (callbacks.compile_method);
673 	res = callbacks.compile_method (method, error);
674 	return res;
675 }
676 
677 gpointer
mono_runtime_create_jump_trampoline(MonoDomain * domain,MonoMethod * method,gboolean add_sync_wrapper,MonoError * error)678 mono_runtime_create_jump_trampoline (MonoDomain *domain, MonoMethod *method, gboolean add_sync_wrapper, MonoError *error)
679 {
680 	gpointer res;
681 
682 	MONO_REQ_GC_NEUTRAL_MODE;
683 
684 	error_init (error);
685 	res = callbacks.create_jump_trampoline (domain, method, add_sync_wrapper, error);
686 	return res;
687 }
688 
689 gpointer
mono_runtime_create_delegate_trampoline(MonoClass * klass)690 mono_runtime_create_delegate_trampoline (MonoClass *klass)
691 {
692 	MONO_REQ_GC_NEUTRAL_MODE
693 
694 	g_assert (callbacks.create_delegate_trampoline);
695 	return callbacks.create_delegate_trampoline (mono_domain_get (), klass);
696 }
697 
698 /**
699  * mono_runtime_free_method:
700  * \param domain domain where the method is hosted
701  * \param method method to release
702  * This routine is invoked to free the resources associated with
703  * a method that has been JIT compiled.  This is used to discard
704  * methods that were used only temporarily (for example, used in marshalling)
705  */
706 void
mono_runtime_free_method(MonoDomain * domain,MonoMethod * method)707 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
708 {
709 	MONO_REQ_GC_NEUTRAL_MODE
710 
711 	if (callbacks.free_method)
712 		callbacks.free_method (domain, method);
713 
714 	mono_method_clear_object (domain, method);
715 
716 	mono_free_method (method);
717 }
718 
719 /*
720  * The vtables in the root appdomain are assumed to be reachable by other
721  * roots, and we don't use typed allocation in the other domains.
722  */
723 
724 /* The sync block is no longer a GC pointer */
725 #define GC_HEADER_BITMAP (0)
726 
727 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
728 
729 static gsize*
compute_class_bitmap(MonoClass * klass,gsize * bitmap,int size,int offset,int * max_set,gboolean static_fields)730 compute_class_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
731 {
732 	MONO_REQ_GC_NEUTRAL_MODE;
733 
734 	MonoClassField *field;
735 	MonoClass *p;
736 	guint32 pos;
737 	int max_size;
738 
739 	if (static_fields)
740 		max_size = mono_class_data_size (klass) / sizeof (gpointer);
741 	else
742 		max_size = klass->instance_size / sizeof (gpointer);
743 	if (max_size > size) {
744 		g_assert (offset <= 0);
745 		bitmap = (gsize *)g_malloc0 ((max_size + BITMAP_EL_SIZE - 1) / BITMAP_EL_SIZE * sizeof (gsize));
746 		size = max_size;
747 	}
748 
749 	/* An Ephemeron cannot be marked by sgen */
750 	if (mono_gc_is_moving () && !static_fields && klass->image == mono_defaults.corlib && !strcmp ("Ephemeron", klass->name)) {
751 		*max_set = 0;
752 		memset (bitmap, 0, size / 8);
753 		return bitmap;
754 	}
755 
756 	for (p = klass; p != NULL; p = p->parent) {
757 		gpointer iter = NULL;
758 		while ((field = mono_class_get_fields (p, &iter))) {
759 			MonoType *type;
760 
761 			if (static_fields) {
762 				if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
763 					continue;
764 				if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL)
765 					continue;
766 			} else {
767 				if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
768 					continue;
769 			}
770 			/* FIXME: should not happen, flag as type load error */
771 			if (field->type->byref)
772 				break;
773 
774 			if (static_fields && field->offset == -1)
775 				/* special static */
776 				continue;
777 
778 			pos = field->offset / sizeof (gpointer);
779 			pos += offset;
780 
781 			type = mono_type_get_underlying_type (field->type);
782 			switch (type->type) {
783 			case MONO_TYPE_U:
784 			case MONO_TYPE_I:
785 			case MONO_TYPE_PTR:
786 			case MONO_TYPE_FNPTR:
787 				break;
788 			case MONO_TYPE_STRING:
789 			case MONO_TYPE_SZARRAY:
790 			case MONO_TYPE_CLASS:
791 			case MONO_TYPE_OBJECT:
792 			case MONO_TYPE_ARRAY:
793 				g_assert ((field->offset % sizeof(gpointer)) == 0);
794 
795 				g_assert (pos < size || pos <= max_size);
796 				bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
797 				*max_set = MAX (*max_set, pos);
798 				break;
799 			case MONO_TYPE_GENERICINST:
800 				if (!mono_type_generic_inst_is_valuetype (type)) {
801 					g_assert ((field->offset % sizeof(gpointer)) == 0);
802 
803 					bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
804 					*max_set = MAX (*max_set, pos);
805 					break;
806 				} else {
807 					/* fall through */
808 				}
809 			case MONO_TYPE_VALUETYPE: {
810 				MonoClass *fclass = mono_class_from_mono_type (field->type);
811 				if (fclass->has_references) {
812 					/* remove the object header */
813 					compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
814 				}
815 				break;
816 			}
817 			case MONO_TYPE_I1:
818 			case MONO_TYPE_U1:
819 			case MONO_TYPE_I2:
820 			case MONO_TYPE_U2:
821 			case MONO_TYPE_I4:
822 			case MONO_TYPE_U4:
823 			case MONO_TYPE_I8:
824 			case MONO_TYPE_U8:
825 			case MONO_TYPE_R4:
826 			case MONO_TYPE_R8:
827 			case MONO_TYPE_BOOLEAN:
828 			case MONO_TYPE_CHAR:
829 				break;
830 			default:
831 				g_error ("compute_class_bitmap: Invalid type %x for field %s:%s\n", type->type, mono_type_get_full_name (field->parent), field->name);
832 				break;
833 			}
834 		}
835 		if (static_fields)
836 			break;
837 	}
838 	return bitmap;
839 }
840 
841 /**
842  * mono_class_compute_bitmap:
843  *
844  * Mono internal function to compute a bitmap of reference fields in a class.
845  */
846 gsize*
mono_class_compute_bitmap(MonoClass * klass,gsize * bitmap,int size,int offset,int * max_set,gboolean static_fields)847 mono_class_compute_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
848 {
849 	MONO_REQ_GC_NEUTRAL_MODE;
850 
851 	return compute_class_bitmap (klass, bitmap, size, offset, max_set, static_fields);
852 }
853 
854 #if 0
855 /*
856  * similar to the above, but sets the bits in the bitmap for any non-ref field
857  * and ignores static fields
858  */
859 static gsize*
860 compute_class_non_ref_bitmap (MonoClass *klass, gsize *bitmap, int size, int offset)
861 {
862 	MonoClassField *field;
863 	MonoClass *p;
864 	guint32 pos, pos2;
865 	int max_size;
866 
867 	max_size = class->instance_size / sizeof (gpointer);
868 	if (max_size >= size) {
869 		bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
870 	}
871 
872 	for (p = class; p != NULL; p = p->parent) {
873 		gpointer iter = NULL;
874 		while ((field = mono_class_get_fields (p, &iter))) {
875 			MonoType *type;
876 
877 			if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
878 				continue;
879 			/* FIXME: should not happen, flag as type load error */
880 			if (field->type->byref)
881 				break;
882 
883 			pos = field->offset / sizeof (gpointer);
884 			pos += offset;
885 
886 			type = mono_type_get_underlying_type (field->type);
887 			switch (type->type) {
888 #if SIZEOF_VOID_P == 8
889 			case MONO_TYPE_I:
890 			case MONO_TYPE_U:
891 			case MONO_TYPE_PTR:
892 			case MONO_TYPE_FNPTR:
893 #endif
894 			case MONO_TYPE_I8:
895 			case MONO_TYPE_U8:
896 			case MONO_TYPE_R8:
897 				if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
898 					pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
899 					bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
900 				}
901 				/* fall through */
902 #if SIZEOF_VOID_P == 4
903 			case MONO_TYPE_I:
904 			case MONO_TYPE_U:
905 			case MONO_TYPE_PTR:
906 			case MONO_TYPE_FNPTR:
907 #endif
908 			case MONO_TYPE_I4:
909 			case MONO_TYPE_U4:
910 			case MONO_TYPE_R4:
911 				if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
912 					pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
913 					bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
914 				}
915 				/* fall through */
916 			case MONO_TYPE_CHAR:
917 			case MONO_TYPE_I2:
918 			case MONO_TYPE_U2:
919 				if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
920 					pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
921 					bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
922 				}
923 				/* fall through */
924 			case MONO_TYPE_BOOLEAN:
925 			case MONO_TYPE_I1:
926 			case MONO_TYPE_U1:
927 				bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
928 				break;
929 			case MONO_TYPE_STRING:
930 			case MONO_TYPE_SZARRAY:
931 			case MONO_TYPE_CLASS:
932 			case MONO_TYPE_OBJECT:
933 			case MONO_TYPE_ARRAY:
934 				break;
935 			case MONO_TYPE_GENERICINST:
936 				if (!mono_type_generic_inst_is_valuetype (type)) {
937 					break;
938 				} else {
939 					/* fall through */
940 				}
941 			case MONO_TYPE_VALUETYPE: {
942 				MonoClass *fclass = mono_class_from_mono_type (field->type);
943 				/* remove the object header */
944 				compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
945 				break;
946 			}
947 			default:
948 				g_assert_not_reached ();
949 				break;
950 			}
951 		}
952 	}
953 	return bitmap;
954 }
955 
956 /**
957  * mono_class_insecure_overlapping:
958  * check if a class with explicit layout has references and non-references
959  * fields overlapping.
960  *
961  * Returns: TRUE if it is insecure to load the type.
962  */
963 gboolean
964 mono_class_insecure_overlapping (MonoClass *klass)
965 {
966 	int max_set = 0;
967 	gsize *bitmap;
968 	gsize default_bitmap [4] = {0};
969 	gsize *nrbitmap;
970 	gsize default_nrbitmap [4] = {0};
971 	int i, insecure = FALSE;
972 		return FALSE;
973 
974 	bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
975 	nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
976 
977 	for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
978 		int idx = i % (sizeof (bitmap [0]) * 8);
979 		if (bitmap [idx] & nrbitmap [idx]) {
980 			insecure = TRUE;
981 			break;
982 		}
983 	}
984 	if (bitmap != default_bitmap)
985 		g_free (bitmap);
986 	if (nrbitmap != default_nrbitmap)
987 		g_free (nrbitmap);
988 	if (insecure) {
989 		g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
990 		return FALSE;
991 	}
992 	return insecure;
993 }
994 #endif
995 
996 MonoString*
ves_icall_string_alloc(int length)997 ves_icall_string_alloc (int length)
998 {
999 	MonoError error;
1000 	MonoString *str = mono_string_new_size_checked (mono_domain_get (), length, &error);
1001 	mono_error_set_pending_exception (&error);
1002 
1003 	return str;
1004 }
1005 
1006 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
1007 
1008 /* LOCKING: Acquires the loader lock */
1009 /*
1010  * Sets the following fields in KLASS:
1011  * - gc_desc
1012  * - gc_descr_inited
1013  */
1014 void
mono_class_compute_gc_descriptor(MonoClass * klass)1015 mono_class_compute_gc_descriptor (MonoClass *klass)
1016 {
1017 	MONO_REQ_GC_NEUTRAL_MODE;
1018 
1019 	int max_set = 0;
1020 	gsize *bitmap;
1021 	gsize default_bitmap [4] = {0};
1022 	MonoGCDescriptor gc_descr;
1023 
1024 	if (!klass->inited)
1025 		mono_class_init (klass);
1026 
1027 	if (klass->gc_descr_inited)
1028 		return;
1029 
1030 	bitmap = default_bitmap;
1031 	if (klass == mono_defaults.string_class) {
1032 		gc_descr = mono_gc_make_descr_for_string (bitmap, 2);
1033 	} else if (klass->rank) {
1034 		mono_class_compute_gc_descriptor (klass->element_class);
1035 		if (MONO_TYPE_IS_REFERENCE (&klass->element_class->byval_arg)) {
1036 			gsize abm = 1;
1037 			gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, &abm, 1, sizeof (gpointer));
1038 			/*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1039 				class->name_space, class->name);*/
1040 		} else {
1041 			/* remove the object header */
1042 			bitmap = compute_class_bitmap (klass->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
1043 			gc_descr = mono_gc_make_descr_for_array (klass->byval_arg.type == MONO_TYPE_SZARRAY, bitmap, mono_array_element_size (klass) / sizeof (gpointer), mono_array_element_size (klass));
1044 			/*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
1045 				class->name_space, class->name);*/
1046 		}
1047 	} else {
1048 		/*static int count = 0;
1049 		if (count++ > 58)
1050 			return;*/
1051 		bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
1052 		/*
1053 		if (class->gc_descr == MONO_GC_DESCRIPTOR_NULL)
1054 			g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);
1055 		*/
1056 		/*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
1057 
1058 		if (klass->has_weak_fields) {
1059 			gsize *weak_bitmap = NULL;
1060 			int weak_bitmap_nbits = 0;
1061 
1062 			weak_bitmap = (gsize *)mono_class_alloc0 (klass, klass->instance_size / sizeof (gsize));
1063 			if (mono_class_has_static_metadata (klass)) {
1064 				for (MonoClass *p = klass; p != NULL; p = p->parent) {
1065 					gpointer iter = NULL;
1066 					guint32 first_field_idx = mono_class_get_first_field_idx (p);
1067 					MonoClassField *field;
1068 
1069 					while ((field = mono_class_get_fields (p, &iter))) {
1070 						guint32 field_idx = first_field_idx + (field - p->fields);
1071 						if (MONO_TYPE_IS_REFERENCE (field->type) && mono_assembly_is_weak_field (p->image, field_idx + 1)) {
1072 							int pos = field->offset / sizeof (gpointer);
1073 							if (pos + 1 > weak_bitmap_nbits)
1074 								weak_bitmap_nbits = pos + 1;
1075 							weak_bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
1076 						}
1077 					}
1078 				}
1079 			}
1080 
1081 			for (int pos = 0; pos < weak_bitmap_nbits; ++pos) {
1082 				if (weak_bitmap [pos / BITMAP_EL_SIZE] & ((gsize)1) << (pos % BITMAP_EL_SIZE)) {
1083 					/* Clear the normal bitmap so these refs don't keep an object alive */
1084 					bitmap [pos / BITMAP_EL_SIZE] &= ~(((gsize)1) << (pos % BITMAP_EL_SIZE));
1085 				}
1086 			}
1087 
1088 			mono_loader_lock ();
1089 			mono_class_set_weak_bitmap (klass, weak_bitmap_nbits, weak_bitmap);
1090 			mono_loader_unlock ();
1091 		}
1092 
1093 		gc_descr = mono_gc_make_descr_for_object (bitmap, max_set + 1, klass->instance_size);
1094 	}
1095 
1096 	if (bitmap != default_bitmap)
1097 		g_free (bitmap);
1098 
1099 	/* Publish the data */
1100 	mono_loader_lock ();
1101 	klass->gc_descr = gc_descr;
1102 	mono_memory_barrier ();
1103 	klass->gc_descr_inited = TRUE;
1104 	mono_loader_unlock ();
1105 }
1106 
1107 /**
1108  * field_is_special_static:
1109  * @fklass: The MonoClass to look up.
1110  * @field: The MonoClassField describing the field.
1111  *
1112  * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
1113  * SPECIAL_STATIC_NONE otherwise.
1114  */
1115 static gint32
field_is_special_static(MonoClass * fklass,MonoClassField * field)1116 field_is_special_static (MonoClass *fklass, MonoClassField *field)
1117 {
1118 	MONO_REQ_GC_NEUTRAL_MODE;
1119 
1120 	MonoError error;
1121 	MonoCustomAttrInfo *ainfo;
1122 	int i;
1123 	ainfo = mono_custom_attrs_from_field_checked (fklass, field, &error);
1124 	mono_error_cleanup (&error); /* FIXME don't swallow the error? */
1125 	if (!ainfo)
1126 		return FALSE;
1127 	for (i = 0; i < ainfo->num_attrs; ++i) {
1128 		MonoClass *klass = ainfo->attrs [i].ctor->klass;
1129 		if (klass->image == mono_defaults.corlib) {
1130 			if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
1131 				mono_custom_attrs_free (ainfo);
1132 				return SPECIAL_STATIC_THREAD;
1133 			}
1134 			else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
1135 				mono_custom_attrs_free (ainfo);
1136 				return SPECIAL_STATIC_CONTEXT;
1137 			}
1138 		}
1139 	}
1140 	mono_custom_attrs_free (ainfo);
1141 	return SPECIAL_STATIC_NONE;
1142 }
1143 
1144 #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
1145 #define mix(a,b,c) { \
1146 	a -= c;  a ^= rot(c, 4);  c += b; \
1147 	b -= a;  b ^= rot(a, 6);  a += c; \
1148 	c -= b;  c ^= rot(b, 8);  b += a; \
1149 	a -= c;  a ^= rot(c,16);  c += b; \
1150 	b -= a;  b ^= rot(a,19);  a += c; \
1151 	c -= b;  c ^= rot(b, 4);  b += a; \
1152 }
1153 #define final(a,b,c) { \
1154 	c ^= b; c -= rot(b,14); \
1155 	a ^= c; a -= rot(c,11); \
1156 	b ^= a; b -= rot(a,25); \
1157 	c ^= b; c -= rot(b,16); \
1158 	a ^= c; a -= rot(c,4);  \
1159 	b ^= a; b -= rot(a,14); \
1160 	c ^= b; c -= rot(b,24); \
1161 }
1162 
1163 /*
1164  * mono_method_get_imt_slot:
1165  *
1166  *   The IMT slot is embedded into AOTed code, so this must return the same value
1167  * for the same method across all executions. This means:
1168  * - pointers shouldn't be used as hash values.
1169  * - mono_metadata_str_hash () should be used for hashing strings.
1170  */
1171 guint32
mono_method_get_imt_slot(MonoMethod * method)1172 mono_method_get_imt_slot (MonoMethod *method)
1173 {
1174 	MONO_REQ_GC_NEUTRAL_MODE;
1175 
1176 	MonoMethodSignature *sig;
1177 	int hashes_count;
1178 	guint32 *hashes_start, *hashes;
1179 	guint32 a, b, c;
1180 	int i;
1181 
1182 	/* This can be used to stress tests the collision code */
1183 	//return 0;
1184 
1185 	/*
1186 	 * We do this to simplify generic sharing.  It will hurt
1187 	 * performance in cases where a class implements two different
1188 	 * instantiations of the same generic interface.
1189 	 * The code in build_imt_slots () depends on this.
1190 	 */
1191 	if (method->is_inflated)
1192 		method = ((MonoMethodInflated*)method)->declaring;
1193 
1194 	sig = mono_method_signature (method);
1195 	hashes_count = sig->param_count + 4;
1196 	hashes_start = (guint32 *)g_malloc (hashes_count * sizeof (guint32));
1197 	hashes = hashes_start;
1198 
1199 	if (! MONO_CLASS_IS_INTERFACE (method->klass)) {
1200 		g_error ("mono_method_get_imt_slot: %s.%s.%s is not an interface MonoMethod",
1201 				method->klass->name_space, method->klass->name, method->name);
1202 	}
1203 
1204 	/* Initialize hashes */
1205 	hashes [0] = mono_metadata_str_hash (method->klass->name);
1206 	hashes [1] = mono_metadata_str_hash (method->klass->name_space);
1207 	hashes [2] = mono_metadata_str_hash (method->name);
1208 	hashes [3] = mono_metadata_type_hash (sig->ret);
1209 	for (i = 0; i < sig->param_count; i++) {
1210 		hashes [4 + i] = mono_metadata_type_hash (sig->params [i]);
1211 	}
1212 
1213 	/* Setup internal state */
1214 	a = b = c = 0xdeadbeef + (((guint32)hashes_count)<<2);
1215 
1216 	/* Handle most of the hashes */
1217 	while (hashes_count > 3) {
1218 		a += hashes [0];
1219 		b += hashes [1];
1220 		c += hashes [2];
1221 		mix (a,b,c);
1222 		hashes_count -= 3;
1223 		hashes += 3;
1224 	}
1225 
1226 	/* Handle the last 3 hashes (all the case statements fall through) */
1227 	switch (hashes_count) {
1228 	case 3 : c += hashes [2];
1229 	case 2 : b += hashes [1];
1230 	case 1 : a += hashes [0];
1231 		final (a,b,c);
1232 	case 0: /* nothing left to add */
1233 		break;
1234 	}
1235 
1236 	g_free (hashes_start);
1237 	/* Report the result */
1238 	return c % MONO_IMT_SIZE;
1239 }
1240 #undef rot
1241 #undef mix
1242 #undef final
1243 
1244 #define DEBUG_IMT 0
1245 
1246 static void
add_imt_builder_entry(MonoImtBuilderEntry ** imt_builder,MonoMethod * method,guint32 * imt_collisions_bitmap,int vtable_slot,int slot_num)1247 add_imt_builder_entry (MonoImtBuilderEntry **imt_builder, MonoMethod *method, guint32 *imt_collisions_bitmap, int vtable_slot, int slot_num) {
1248 	MONO_REQ_GC_NEUTRAL_MODE;
1249 
1250 	guint32 imt_slot = mono_method_get_imt_slot (method);
1251 	MonoImtBuilderEntry *entry;
1252 
1253 	if (slot_num >= 0 && imt_slot != slot_num) {
1254 		/* we build just a single imt slot and this is not it */
1255 		return;
1256 	}
1257 
1258 	entry = (MonoImtBuilderEntry *)g_malloc0 (sizeof (MonoImtBuilderEntry));
1259 	entry->key = method;
1260 	entry->value.vtable_slot = vtable_slot;
1261 	entry->next = imt_builder [imt_slot];
1262 	if (imt_builder [imt_slot] != NULL) {
1263 		entry->children = imt_builder [imt_slot]->children + 1;
1264 		if (entry->children == 1) {
1265 			UnlockedIncrement (&mono_stats.imt_slots_with_collisions);
1266 			*imt_collisions_bitmap |= (1 << imt_slot);
1267 		}
1268 	} else {
1269 		entry->children = 0;
1270 		UnlockedIncrement (&mono_stats.imt_used_slots);
1271 	}
1272 	imt_builder [imt_slot] = entry;
1273 #if DEBUG_IMT
1274 	{
1275 	char *method_name = mono_method_full_name (method, TRUE);
1276 	printf ("Added IMT slot for method (%p) %s: imt_slot = %d, vtable_slot = %d, colliding with other %d entries\n",
1277 			method, method_name, imt_slot, vtable_slot, entry->children);
1278 	g_free (method_name);
1279 	}
1280 #endif
1281 }
1282 
1283 #if DEBUG_IMT
1284 static void
print_imt_entry(const char * message,MonoImtBuilderEntry * e,int num)1285 print_imt_entry (const char* message, MonoImtBuilderEntry *e, int num) {
1286 	if (e != NULL) {
1287 		MonoMethod *method = e->key;
1288 		printf ("  * %s [%d]: (%p) '%s.%s.%s'\n",
1289 				message,
1290 				num,
1291 				method,
1292 				method->klass->name_space,
1293 				method->klass->name,
1294 				method->name);
1295 	} else {
1296 		printf ("  * %s: NULL\n", message);
1297 	}
1298 }
1299 #endif
1300 
1301 static int
compare_imt_builder_entries(const void * p1,const void * p2)1302 compare_imt_builder_entries (const void *p1, const void *p2) {
1303 	MonoImtBuilderEntry *e1 = *(MonoImtBuilderEntry**) p1;
1304 	MonoImtBuilderEntry *e2 = *(MonoImtBuilderEntry**) p2;
1305 
1306 	return (e1->key < e2->key) ? -1 : ((e1->key > e2->key) ? 1 : 0);
1307 }
1308 
1309 static int
imt_emit_ir(MonoImtBuilderEntry ** sorted_array,int start,int end,GPtrArray * out_array)1310 imt_emit_ir (MonoImtBuilderEntry **sorted_array, int start, int end, GPtrArray *out_array)
1311 {
1312 	MONO_REQ_GC_NEUTRAL_MODE;
1313 
1314 	int count = end - start;
1315 	int chunk_start = out_array->len;
1316 	if (count < 4) {
1317 		int i;
1318 		for (i = start; i < end; ++i) {
1319 			MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1320 			item->key = sorted_array [i]->key;
1321 			item->value = sorted_array [i]->value;
1322 			item->has_target_code = sorted_array [i]->has_target_code;
1323 			item->is_equals = TRUE;
1324 			if (i < end - 1)
1325 				item->check_target_idx = out_array->len + 1;
1326 			else
1327 				item->check_target_idx = 0;
1328 			g_ptr_array_add (out_array, item);
1329 		}
1330 	} else {
1331 		int middle = start + count / 2;
1332 		MonoIMTCheckItem *item = g_new0 (MonoIMTCheckItem, 1);
1333 
1334 		item->key = sorted_array [middle]->key;
1335 		item->is_equals = FALSE;
1336 		g_ptr_array_add (out_array, item);
1337 		imt_emit_ir (sorted_array, start, middle, out_array);
1338 		item->check_target_idx = imt_emit_ir (sorted_array, middle, end, out_array);
1339 	}
1340 	return chunk_start;
1341 }
1342 
1343 static GPtrArray*
imt_sort_slot_entries(MonoImtBuilderEntry * entries)1344 imt_sort_slot_entries (MonoImtBuilderEntry *entries) {
1345 	MONO_REQ_GC_NEUTRAL_MODE;
1346 
1347 	int number_of_entries = entries->children + 1;
1348 	MonoImtBuilderEntry **sorted_array = (MonoImtBuilderEntry **)g_malloc (sizeof (MonoImtBuilderEntry*) * number_of_entries);
1349 	GPtrArray *result = g_ptr_array_new ();
1350 	MonoImtBuilderEntry *current_entry;
1351 	int i;
1352 
1353 	for (current_entry = entries, i = 0; current_entry != NULL; current_entry = current_entry->next, i++) {
1354 		sorted_array [i] = current_entry;
1355 	}
1356 	qsort (sorted_array, number_of_entries, sizeof (MonoImtBuilderEntry*), compare_imt_builder_entries);
1357 
1358 	/*for (i = 0; i < number_of_entries; i++) {
1359 		print_imt_entry (" sorted array:", sorted_array [i], i);
1360 	}*/
1361 
1362 	imt_emit_ir (sorted_array, 0, number_of_entries, result);
1363 
1364 	g_free (sorted_array);
1365 	return result;
1366 }
1367 
1368 static gpointer
initialize_imt_slot(MonoVTable * vtable,MonoDomain * domain,MonoImtBuilderEntry * imt_builder_entry,gpointer fail_tramp)1369 initialize_imt_slot (MonoVTable *vtable, MonoDomain *domain, MonoImtBuilderEntry *imt_builder_entry, gpointer fail_tramp)
1370 {
1371 	MONO_REQ_GC_NEUTRAL_MODE;
1372 
1373 	if (imt_builder_entry != NULL) {
1374 		if (imt_builder_entry->children == 0 && !fail_tramp && !always_build_imt_trampolines) {
1375 			/* No collision, return the vtable slot contents */
1376 			return vtable->vtable [imt_builder_entry->value.vtable_slot];
1377 		} else {
1378 			/* Collision, build the trampoline */
1379 			GPtrArray *imt_ir = imt_sort_slot_entries (imt_builder_entry);
1380 			gpointer result;
1381 			int i;
1382 			result = imt_trampoline_builder (vtable, domain,
1383 				(MonoIMTCheckItem**)imt_ir->pdata, imt_ir->len, fail_tramp);
1384 			for (i = 0; i < imt_ir->len; ++i)
1385 				g_free (g_ptr_array_index (imt_ir, i));
1386 			g_ptr_array_free (imt_ir, TRUE);
1387 			return result;
1388 		}
1389 	} else {
1390 		if (fail_tramp)
1391 			return fail_tramp;
1392 		else
1393 			/* Empty slot */
1394 			return NULL;
1395 	}
1396 }
1397 
1398 static MonoImtBuilderEntry*
1399 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot);
1400 
1401 /*
1402  * LOCKING: requires the loader and domain locks.
1403  *
1404 */
1405 static void
build_imt_slots(MonoClass * klass,MonoVTable * vt,MonoDomain * domain,gpointer * imt,GSList * extra_interfaces,int slot_num)1406 build_imt_slots (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces, int slot_num)
1407 {
1408 	MONO_REQ_GC_NEUTRAL_MODE;
1409 
1410 	int i;
1411 	GSList *list_item;
1412 	guint32 imt_collisions_bitmap = 0;
1413 	MonoImtBuilderEntry **imt_builder = (MonoImtBuilderEntry **)g_calloc (MONO_IMT_SIZE, sizeof (MonoImtBuilderEntry*));
1414 	int method_count = 0;
1415 	gboolean record_method_count_for_max_collisions = FALSE;
1416 	gboolean has_generic_virtual = FALSE, has_variant_iface = FALSE;
1417 
1418 #if DEBUG_IMT
1419 	printf ("Building IMT for class %s.%s slot %d\n", klass->name_space, klass->name, slot_num);
1420 #endif
1421 	for (i = 0; i < klass->interface_offsets_count; ++i) {
1422 		MonoClass *iface = klass->interfaces_packed [i];
1423 		int interface_offset = klass->interface_offsets_packed [i];
1424 		int method_slot_in_interface, vt_slot;
1425 
1426 		if (mono_class_has_variant_generic_params (iface))
1427 			has_variant_iface = TRUE;
1428 
1429 		mono_class_setup_methods (iface);
1430 		vt_slot = interface_offset;
1431 		int mcount = mono_class_get_method_count (iface);
1432 		for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1433 			MonoMethod *method;
1434 
1435 			if (slot_num >= 0 && mono_class_is_ginst (iface)) {
1436 				/*
1437 				 * The imt slot of the method is the same as for its declaring method,
1438 				 * see the comment in mono_method_get_imt_slot (), so we can
1439 				 * avoid inflating methods which will be discarded by
1440 				 * add_imt_builder_entry anyway.
1441 				 */
1442 				method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface);
1443 				if (mono_method_get_imt_slot (method) != slot_num) {
1444 					vt_slot ++;
1445 					continue;
1446 				}
1447 			}
1448 			method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1449 			if (method->is_generic) {
1450 				has_generic_virtual = TRUE;
1451 				vt_slot ++;
1452 				continue;
1453 			}
1454 
1455 			if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) {
1456 				add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, vt_slot, slot_num);
1457 				vt_slot ++;
1458 			}
1459 		}
1460 	}
1461 	if (extra_interfaces) {
1462 		int interface_offset = klass->vtable_size;
1463 
1464 		for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1465 			MonoClass* iface = (MonoClass *)list_item->data;
1466 			int method_slot_in_interface;
1467 			int mcount = mono_class_get_method_count (iface);
1468 			for (method_slot_in_interface = 0; method_slot_in_interface < mcount; method_slot_in_interface++) {
1469 				MonoMethod *method = mono_class_get_method_by_index (iface, method_slot_in_interface);
1470 
1471 				if (method->is_generic)
1472 					has_generic_virtual = TRUE;
1473 				add_imt_builder_entry (imt_builder, method, &imt_collisions_bitmap, interface_offset + method_slot_in_interface, slot_num);
1474 			}
1475 			interface_offset += mcount;
1476 		}
1477 	}
1478 	for (i = 0; i < MONO_IMT_SIZE; ++i) {
1479 		/* overwrite the imt slot only if we're building all the entries or if
1480 		 * we're building this specific one
1481 		 */
1482 		if (slot_num < 0 || i == slot_num) {
1483 			MonoImtBuilderEntry *entries = get_generic_virtual_entries (domain, &imt [i]);
1484 
1485 			if (entries) {
1486 				if (imt_builder [i]) {
1487 					MonoImtBuilderEntry *entry;
1488 
1489 					/* Link entries with imt_builder [i] */
1490 					for (entry = entries; entry->next; entry = entry->next) {
1491 #if DEBUG_IMT
1492 						MonoMethod *method = (MonoMethod*)entry->key;
1493 						char *method_name = mono_method_full_name (method, TRUE);
1494 						printf ("Added extra entry for method (%p) %s: imt_slot = %d\n", method, method_name, i);
1495 						g_free (method_name);
1496 #endif
1497 					}
1498 					entry->next = imt_builder [i];
1499 					entries->children += imt_builder [i]->children + 1;
1500 				}
1501 				imt_builder [i] = entries;
1502 			}
1503 
1504 			if (has_generic_virtual || has_variant_iface) {
1505 				/*
1506 				 * There might be collisions later when the the trampoline is expanded.
1507 				 */
1508 				imt_collisions_bitmap |= (1 << i);
1509 
1510 				/*
1511 				 * The IMT trampoline might be called with an instance of one of the
1512 				 * generic virtual methods, so has to fallback to the IMT trampoline.
1513 				 */
1514 				imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], callbacks.get_imt_trampoline (vt, i));
1515 			} else {
1516 				imt [i] = initialize_imt_slot (vt, domain, imt_builder [i], NULL);
1517 			}
1518 #if DEBUG_IMT
1519 			printf ("initialize_imt_slot[%d]: %p methods %d\n", i, imt [i], imt_builder [i]->children + 1);
1520 #endif
1521 		}
1522 
1523 		if (imt_builder [i] != NULL) {
1524 			int methods_in_slot = imt_builder [i]->children + 1;
1525 			if (methods_in_slot > UnlockedRead (&mono_stats.imt_max_collisions_in_slot)) {
1526 				UnlockedWrite (&mono_stats.imt_max_collisions_in_slot, methods_in_slot);
1527 				record_method_count_for_max_collisions = TRUE;
1528 			}
1529 			method_count += methods_in_slot;
1530 		}
1531 	}
1532 
1533 	UnlockedAdd (&mono_stats.imt_number_of_methods, method_count);
1534 	if (record_method_count_for_max_collisions) {
1535 		UnlockedWrite (&mono_stats.imt_method_count_when_max_collisions, method_count);
1536 	}
1537 
1538 	for (i = 0; i < MONO_IMT_SIZE; i++) {
1539 		MonoImtBuilderEntry* entry = imt_builder [i];
1540 		while (entry != NULL) {
1541 			MonoImtBuilderEntry* next = entry->next;
1542 			g_free (entry);
1543 			entry = next;
1544 		}
1545 	}
1546 	g_free (imt_builder);
1547 	/* we OR the bitmap since we may build just a single imt slot at a time */
1548 	vt->imt_collisions_bitmap |= imt_collisions_bitmap;
1549 }
1550 
1551 static void
build_imt(MonoClass * klass,MonoVTable * vt,MonoDomain * domain,gpointer * imt,GSList * extra_interfaces)1552 build_imt (MonoClass *klass, MonoVTable *vt, MonoDomain *domain, gpointer* imt, GSList *extra_interfaces) {
1553 	MONO_REQ_GC_NEUTRAL_MODE;
1554 
1555 	build_imt_slots (klass, vt, domain, imt, extra_interfaces, -1);
1556 }
1557 
1558 /**
1559  * mono_vtable_build_imt_slot:
1560  * \param vtable virtual object table struct
1561  * \param imt_slot slot in the IMT table
1562  * Fill the given \p imt_slot in the IMT table of \p vtable with
1563  * a trampoline or a trampoline for the case of collisions.
1564  * This is part of the internal mono API.
1565  * LOCKING: Take the domain lock.
1566  */
1567 void
mono_vtable_build_imt_slot(MonoVTable * vtable,int imt_slot)1568 mono_vtable_build_imt_slot (MonoVTable* vtable, int imt_slot)
1569 {
1570 	MONO_REQ_GC_NEUTRAL_MODE;
1571 
1572 	gpointer *imt = (gpointer*)vtable;
1573 	imt -= MONO_IMT_SIZE;
1574 	g_assert (imt_slot >= 0 && imt_slot < MONO_IMT_SIZE);
1575 
1576 	/* no support for extra interfaces: the proxy objects will need
1577 	 * to build the complete IMT
1578 	 * Update and heck needs to ahppen inside the proper domain lock, as all
1579 	 * the changes made to a MonoVTable.
1580 	 */
1581 	mono_loader_lock (); /*FIXME build_imt_slots requires the loader lock.*/
1582 	mono_domain_lock (vtable->domain);
1583 	/* we change the slot only if it wasn't changed from the generic imt trampoline already */
1584 	if (!callbacks.imt_entry_inited (vtable, imt_slot))
1585 		build_imt_slots (vtable->klass, vtable, vtable->domain, imt, NULL, imt_slot);
1586 	mono_domain_unlock (vtable->domain);
1587 	mono_loader_unlock ();
1588 }
1589 
1590 #define THUNK_THRESHOLD		10
1591 
1592 /**
1593  * mono_method_alloc_generic_virtual_trampoline:
1594  * \param domain a domain
1595  * \param size size in bytes
1596  * Allocs \p size bytes to be used for the code of a generic virtual
1597  * trampoline.  It's either allocated from the domain's code manager or
1598  * reused from a previously invalidated piece.
1599  * LOCKING: The domain lock must be held.
1600  */
1601 gpointer
mono_method_alloc_generic_virtual_trampoline(MonoDomain * domain,int size)1602 mono_method_alloc_generic_virtual_trampoline (MonoDomain *domain, int size)
1603 {
1604 	MONO_REQ_GC_NEUTRAL_MODE;
1605 
1606 	static gboolean inited = FALSE;
1607 	static int generic_virtual_trampolines_size = 0;
1608 
1609 	if (!inited) {
1610 		mono_counters_register ("Generic virtual trampoline bytes",
1611 				MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &generic_virtual_trampolines_size);
1612 		inited = TRUE;
1613 	}
1614 	generic_virtual_trampolines_size += size;
1615 
1616 	return mono_domain_code_reserve (domain, size);
1617 }
1618 
1619 typedef struct _GenericVirtualCase {
1620 	MonoMethod *method;
1621 	gpointer code;
1622 	int count;
1623 	struct _GenericVirtualCase *next;
1624 } GenericVirtualCase;
1625 
1626 /*
1627  * get_generic_virtual_entries:
1628  *
1629  *   Return IMT entries for the generic virtual method instances and
1630  *   variant interface methods for vtable slot
1631  * VTABLE_SLOT.
1632  */
1633 static MonoImtBuilderEntry*
get_generic_virtual_entries(MonoDomain * domain,gpointer * vtable_slot)1634 get_generic_virtual_entries (MonoDomain *domain, gpointer *vtable_slot)
1635 {
1636 	MONO_REQ_GC_NEUTRAL_MODE;
1637 
1638   	GenericVirtualCase *list;
1639  	MonoImtBuilderEntry *entries;
1640 
1641  	mono_domain_lock (domain);
1642  	if (!domain->generic_virtual_cases)
1643  		domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1644 
1645 	list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1646 
1647  	entries = NULL;
1648  	for (; list; list = list->next) {
1649  		MonoImtBuilderEntry *entry;
1650 
1651  		if (list->count < THUNK_THRESHOLD)
1652  			continue;
1653 
1654  		entry = g_new0 (MonoImtBuilderEntry, 1);
1655  		entry->key = list->method;
1656  		entry->value.target_code = mono_get_addr_from_ftnptr (list->code);
1657  		entry->has_target_code = 1;
1658  		if (entries)
1659  			entry->children = entries->children + 1;
1660  		entry->next = entries;
1661  		entries = entry;
1662  	}
1663 
1664  	mono_domain_unlock (domain);
1665 
1666  	/* FIXME: Leaking memory ? */
1667  	return entries;
1668 }
1669 
1670 /**
1671  * \param domain a domain
1672  * \param vtable_slot pointer to the vtable slot
1673  * \param method the inflated generic virtual method
1674  * \param code the method's code
1675  *
1676  * Registers a call via unmanaged code to a generic virtual method
1677  * instantiation or variant interface method.  If the number of calls reaches a threshold
1678  * (THUNK_THRESHOLD), the method is added to the vtable slot's generic
1679  * virtual method trampoline.
1680  */
1681 void
mono_method_add_generic_virtual_invocation(MonoDomain * domain,MonoVTable * vtable,gpointer * vtable_slot,MonoMethod * method,gpointer code)1682 mono_method_add_generic_virtual_invocation (MonoDomain *domain, MonoVTable *vtable,
1683 											gpointer *vtable_slot,
1684 											MonoMethod *method, gpointer code)
1685 {
1686 	MONO_REQ_GC_NEUTRAL_MODE;
1687 
1688 	static gboolean inited = FALSE;
1689 	static int num_added = 0;
1690 	static int num_freed = 0;
1691 
1692 	GenericVirtualCase *gvc, *list;
1693 	MonoImtBuilderEntry *entries;
1694 	int i;
1695 	GPtrArray *sorted;
1696 
1697 	mono_domain_lock (domain);
1698 	if (!domain->generic_virtual_cases)
1699 		domain->generic_virtual_cases = g_hash_table_new (mono_aligned_addr_hash, NULL);
1700 
1701 	if (!inited) {
1702 		mono_counters_register ("Generic virtual cases", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_added);
1703 		mono_counters_register ("Freed IMT trampolines", MONO_COUNTER_GENERICS | MONO_COUNTER_INT, &num_freed);
1704 		inited = TRUE;
1705 	}
1706 
1707 	/* Check whether the case was already added */
1708 	list = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1709 	gvc = list;
1710 	while (gvc) {
1711 		if (gvc->method == method)
1712 			break;
1713 		gvc = gvc->next;
1714 	}
1715 
1716 	/* If not found, make a new one */
1717 	if (!gvc) {
1718 		gvc = (GenericVirtualCase *)mono_domain_alloc (domain, sizeof (GenericVirtualCase));
1719 		gvc->method = method;
1720 		gvc->code = code;
1721 		gvc->count = 0;
1722 		gvc->next = (GenericVirtualCase *)g_hash_table_lookup (domain->generic_virtual_cases, vtable_slot);
1723 
1724 		g_hash_table_insert (domain->generic_virtual_cases, vtable_slot, gvc);
1725 
1726 		num_added++;
1727 	}
1728 
1729 	if (++gvc->count == THUNK_THRESHOLD) {
1730 		gpointer *old_thunk = (void **)*vtable_slot;
1731 		gpointer vtable_trampoline = NULL;
1732 		gpointer imt_trampoline = NULL;
1733 
1734 		if ((gpointer)vtable_slot < (gpointer)vtable) {
1735 			int displacement = (gpointer*)vtable_slot - (gpointer*)vtable;
1736 			int imt_slot = MONO_IMT_SIZE + displacement;
1737 
1738 			/* Force the rebuild of the trampoline at the next call */
1739 			imt_trampoline = callbacks.get_imt_trampoline (vtable, imt_slot);
1740 			*vtable_slot = imt_trampoline;
1741 		} else {
1742 			vtable_trampoline = callbacks.get_vtable_trampoline ? callbacks.get_vtable_trampoline (vtable, (gpointer*)vtable_slot - (gpointer*)vtable->vtable) : NULL;
1743 
1744 			entries = get_generic_virtual_entries (domain, vtable_slot);
1745 
1746 			sorted = imt_sort_slot_entries (entries);
1747 
1748 			*vtable_slot = imt_trampoline_builder (NULL, domain, (MonoIMTCheckItem**)sorted->pdata, sorted->len,
1749 												   vtable_trampoline);
1750 
1751 			while (entries) {
1752 				MonoImtBuilderEntry *next = entries->next;
1753 				g_free (entries);
1754 				entries = next;
1755 			}
1756 
1757 			for (i = 0; i < sorted->len; ++i)
1758 				g_free (g_ptr_array_index (sorted, i));
1759 			g_ptr_array_free (sorted, TRUE);
1760 
1761 			if (old_thunk != vtable_trampoline && old_thunk != imt_trampoline)
1762 				num_freed ++;
1763 		}
1764 	}
1765 
1766 	mono_domain_unlock (domain);
1767 }
1768 
1769 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error);
1770 
1771 /**
1772  * mono_class_vtable:
1773  * \param domain the application domain
1774  * \param class the class to initialize
1775  * VTables are domain specific because we create domain specific code, and
1776  * they contain the domain specific static class data.
1777  * On failure, NULL is returned, and \c class->exception_type is set.
1778  */
1779 MonoVTable *
mono_class_vtable(MonoDomain * domain,MonoClass * klass)1780 mono_class_vtable (MonoDomain *domain, MonoClass *klass)
1781 {
1782 	MonoError error;
1783 	MonoVTable* vtable = mono_class_vtable_full (domain, klass, &error);
1784 	mono_error_cleanup (&error);
1785 	return vtable;
1786 }
1787 
1788 /**
1789  * mono_class_vtable_full:
1790  * \param domain the application domain
1791  * \param class the class to initialize
1792  * \param error set on failure.
1793  * VTables are domain specific because we create domain specific code, and
1794  * they contain the domain specific static class data.
1795  */
1796 MonoVTable *
mono_class_vtable_full(MonoDomain * domain,MonoClass * klass,MonoError * error)1797 mono_class_vtable_full (MonoDomain *domain, MonoClass *klass, MonoError *error)
1798 {
1799 	MONO_REQ_GC_UNSAFE_MODE;
1800 
1801 	MonoClassRuntimeInfo *runtime_info;
1802 
1803 	error_init (error);
1804 
1805 	g_assert (klass);
1806 
1807 	if (mono_class_has_failure (klass)) {
1808 		mono_error_set_for_class_failure (error, klass);
1809 		return NULL;
1810 	}
1811 
1812 	/* this check can be inlined in jitted code, too */
1813 	runtime_info = klass->runtime_info;
1814 	if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1815 		return runtime_info->domain_vtables [domain->domain_id];
1816 	return mono_class_create_runtime_vtable (domain, klass, error);
1817 }
1818 
1819 /**
1820  * mono_class_try_get_vtable:
1821  * \param domain the application domain
1822  * \param class the class to initialize
1823  * This function tries to get the associated vtable from \p class if
1824  * it was already created.
1825  */
1826 MonoVTable *
mono_class_try_get_vtable(MonoDomain * domain,MonoClass * klass)1827 mono_class_try_get_vtable (MonoDomain *domain, MonoClass *klass)
1828 {
1829 	MONO_REQ_GC_NEUTRAL_MODE;
1830 
1831 	MonoClassRuntimeInfo *runtime_info;
1832 
1833 	g_assert (klass);
1834 
1835 	runtime_info = klass->runtime_info;
1836 	if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
1837 		return runtime_info->domain_vtables [domain->domain_id];
1838 	return NULL;
1839 }
1840 
1841 static gpointer*
alloc_vtable(MonoDomain * domain,size_t vtable_size,size_t imt_table_bytes)1842 alloc_vtable (MonoDomain *domain, size_t vtable_size, size_t imt_table_bytes)
1843 {
1844 	MONO_REQ_GC_NEUTRAL_MODE;
1845 
1846 	size_t alloc_offset;
1847 
1848 	/*
1849 	 * We want the pointer to the MonoVTable aligned to 8 bytes because SGen uses three
1850 	 * address bits.  The IMT has an odd number of entries, however, so on 32 bits the
1851 	 * alignment will be off.  In that case we allocate 4 more bytes and skip over them.
1852 	 */
1853 	if (sizeof (gpointer) == 4 && (imt_table_bytes & 7)) {
1854 		g_assert ((imt_table_bytes & 7) == 4);
1855 		vtable_size += 4;
1856 		alloc_offset = 4;
1857 	} else {
1858 		alloc_offset = 0;
1859 	}
1860 
1861 	return (gpointer*) ((char*)mono_domain_alloc0 (domain, vtable_size) + alloc_offset);
1862 }
1863 
1864 static MonoVTable *
mono_class_create_runtime_vtable(MonoDomain * domain,MonoClass * klass,MonoError * error)1865 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoError *error)
1866 {
1867 	MONO_REQ_GC_UNSAFE_MODE;
1868 
1869 	MonoVTable *vt;
1870 	MonoClassRuntimeInfo *runtime_info, *old_info;
1871 	MonoClassField *field;
1872 	char *t;
1873 	int i, vtable_slots;
1874 	size_t imt_table_bytes;
1875 	int gc_bits;
1876 	guint32 vtable_size, class_size;
1877 	gpointer iter;
1878 	gpointer *interface_offsets;
1879 
1880 	error_init (error);
1881 
1882 	mono_loader_lock (); /*FIXME mono_class_init acquires it*/
1883 	mono_domain_lock (domain);
1884 	runtime_info = klass->runtime_info;
1885 	if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
1886 		mono_domain_unlock (domain);
1887 		mono_loader_unlock ();
1888 		return runtime_info->domain_vtables [domain->domain_id];
1889 	}
1890 	if (!klass->inited || mono_class_has_failure (klass)) {
1891 		if (!mono_class_init (klass) || mono_class_has_failure (klass)) {
1892 			mono_domain_unlock (domain);
1893 			mono_loader_unlock ();
1894 			mono_error_set_for_class_failure (error, klass);
1895 			return NULL;
1896 		}
1897 	}
1898 
1899 	/* Array types require that their element type be valid*/
1900 	if (klass->byval_arg.type == MONO_TYPE_ARRAY || klass->byval_arg.type == MONO_TYPE_SZARRAY) {
1901 		MonoClass *element_class = klass->element_class;
1902 		if (!element_class->inited)
1903 			mono_class_init (element_class);
1904 
1905 		/*mono_class_init can leave the vtable layout to be lazily done and we can't afford this here*/
1906 		if (!mono_class_has_failure (element_class) && !element_class->vtable_size)
1907 			mono_class_setup_vtable (element_class);
1908 
1909 		if (mono_class_has_failure (element_class)) {
1910 			/*Can happen if element_class only got bad after mono_class_setup_vtable*/
1911 			if (!mono_class_has_failure (klass))
1912 				mono_class_set_type_load_failure (klass, "");
1913 			mono_domain_unlock (domain);
1914 			mono_loader_unlock ();
1915 			mono_error_set_for_class_failure (error, klass);
1916 			return NULL;
1917 		}
1918 	}
1919 
1920 	/*
1921 	 * For some classes, mono_class_init () already computed klass->vtable_size, and
1922 	 * that is all that is needed because of the vtable trampolines.
1923 	 */
1924 	if (!klass->vtable_size)
1925 		mono_class_setup_vtable (klass);
1926 
1927 	if (mono_class_is_ginst (klass) && !klass->vtable)
1928 		mono_class_check_vtable_constraints (klass, NULL);
1929 
1930 	/* Initialize klass->has_finalize */
1931 	mono_class_has_finalizer (klass);
1932 
1933 	if (mono_class_has_failure (klass)) {
1934 		mono_domain_unlock (domain);
1935 		mono_loader_unlock ();
1936 		mono_error_set_for_class_failure (error, klass);
1937 		return NULL;
1938 	}
1939 
1940 	vtable_slots = klass->vtable_size;
1941 	/* we add an additional vtable slot to store the pointer to static field data only when needed */
1942 	class_size = mono_class_data_size (klass);
1943 	if (class_size)
1944 		vtable_slots++;
1945 
1946 	if (klass->interface_offsets_count) {
1947 		imt_table_bytes = sizeof (gpointer) * (MONO_IMT_SIZE);
1948 		UnlockedIncrement (&mono_stats.imt_number_of_tables);
1949 		UnlockedAdd (&mono_stats.imt_tables_size, imt_table_bytes);
1950 	} else {
1951 		imt_table_bytes = 0;
1952 	}
1953 
1954 	vtable_size = imt_table_bytes + MONO_SIZEOF_VTABLE + vtable_slots * sizeof (gpointer);
1955 
1956 	UnlockedIncrement (&mono_stats.used_class_count);
1957 	UnlockedAdd (&mono_stats.class_vtable_size, vtable_size);
1958 
1959 	interface_offsets = alloc_vtable (domain, vtable_size, imt_table_bytes);
1960 	vt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
1961 	g_assert (!((gsize)vt & 7));
1962 
1963 	vt->klass = klass;
1964 	vt->rank = klass->rank;
1965 	vt->domain = domain;
1966 
1967 	mono_class_compute_gc_descriptor (klass);
1968 	/*
1969 	 * For Boehm:
1970 	 * We can't use typed allocation in the non-root domains, since the
1971 	 * collector needs the GC descriptor stored in the vtable even after
1972 	 * the mempool containing the vtable is destroyed when the domain is
1973 	 * unloaded. An alternative might be to allocate vtables in the GC
1974 	 * heap, but this does not seem to work (it leads to crashes inside
1975 	 * libgc). If that approach is tried, two gc descriptors need to be
1976 	 * allocated for each class: one for the root domain, and one for all
1977 	 * other domains. The second descriptor should contain a bit for the
1978 	 * vtable field in MonoObject, since we can no longer assume the
1979 	 * vtable is reachable by other roots after the appdomain is unloaded.
1980 	 */
1981 	if (!mono_gc_is_moving () && domain != mono_get_root_domain () && !mono_dont_free_domains)
1982 		vt->gc_descr = MONO_GC_DESCRIPTOR_NULL;
1983 	else
1984 		vt->gc_descr = klass->gc_descr;
1985 
1986 	gc_bits = mono_gc_get_vtable_bits (klass);
1987 	g_assert (!(gc_bits & ~((1 << MONO_VTABLE_AVAILABLE_GC_BITS) - 1)));
1988 
1989 	vt->gc_bits = gc_bits;
1990 
1991 	if (class_size) {
1992 		/* we store the static field pointer at the end of the vtable: vt->vtable [class->vtable_size] */
1993 		if (klass->has_static_refs) {
1994 			MonoGCDescriptor statics_gc_descr;
1995 			int max_set = 0;
1996 			gsize default_bitmap [4] = {0};
1997 			gsize *bitmap;
1998 
1999 			bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
2000 			/*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/
2001 			statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1);
2002 			vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables");
2003 			if (bitmap != default_bitmap)
2004 				g_free (bitmap);
2005 		} else {
2006 			vt->vtable [klass->vtable_size] = mono_domain_alloc0 (domain, class_size);
2007 		}
2008 		vt->has_static_fields = TRUE;
2009 		UnlockedAdd (&mono_stats.class_static_data_size, class_size);
2010 	}
2011 
2012 	iter = NULL;
2013 	while ((field = mono_class_get_fields (klass, &iter))) {
2014 		if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2015 			continue;
2016 		if (mono_field_is_deleted (field))
2017 			continue;
2018 		if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2019 			gint32 special_static = klass->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (klass, field);
2020 			if (special_static != SPECIAL_STATIC_NONE) {
2021 				guint32 size, offset;
2022 				gint32 align;
2023 				gsize default_bitmap [4] = {0};
2024 				gsize *bitmap;
2025 				int max_set = 0;
2026 				int numbits;
2027 				MonoClass *fclass;
2028 				if (mono_type_is_reference (field->type)) {
2029 					default_bitmap [0] = 1;
2030 					numbits = 1;
2031 					bitmap = default_bitmap;
2032 				} else if (mono_type_is_struct (field->type)) {
2033 					fclass = mono_class_from_mono_type (field->type);
2034 					bitmap = compute_class_bitmap (fclass, default_bitmap, sizeof (default_bitmap) * 8, - (int)(sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
2035 					numbits = max_set + 1;
2036 				} else {
2037 					default_bitmap [0] = 0;
2038 					numbits = 0;
2039 					bitmap = default_bitmap;
2040 				}
2041 				size = mono_type_size (field->type, &align);
2042 				offset = mono_alloc_special_static_data (special_static, size, align, (uintptr_t*)bitmap, numbits);
2043 				if (!domain->special_static_fields)
2044 					domain->special_static_fields = g_hash_table_new (NULL, NULL);
2045 				g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
2046 				if (bitmap != default_bitmap)
2047 					g_free (bitmap);
2048 				/*
2049 				 * This marks the field as special static to speed up the
2050 				 * checks in mono_field_static_get/set_value ().
2051 				 */
2052 				field->offset = -1;
2053 				continue;
2054 			}
2055 		}
2056 		if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
2057 			MonoClass *fklass = mono_class_from_mono_type (field->type);
2058 			const char *data = mono_field_get_data (field);
2059 
2060 			g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
2061 			t = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
2062 			/* some fields don't really have rva, they are just zeroed (bss? bug #343083) */
2063 			if (!data)
2064 				continue;
2065 			if (fklass->valuetype) {
2066 				memcpy (t, data, mono_class_value_size (fklass, NULL));
2067 			} else {
2068 				/* it's a pointer type: add check */
2069 				g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
2070 				*t = *(char *)data;
2071 			}
2072 			continue;
2073 		}
2074 	}
2075 
2076 	vt->max_interface_id = klass->max_interface_id;
2077 	vt->interface_bitmap = klass->interface_bitmap;
2078 
2079 	//printf ("Initializing VT for class %s (interface_offsets_count = %d)\n",
2080 	//		class->name, klass->interface_offsets_count);
2081 
2082 	/* Initialize vtable */
2083 	if (callbacks.get_vtable_trampoline) {
2084 		// This also covers the AOT case
2085 		for (i = 0; i < klass->vtable_size; ++i) {
2086 			vt->vtable [i] = callbacks.get_vtable_trampoline (vt, i);
2087 		}
2088 	} else {
2089 		mono_class_setup_vtable (klass);
2090 
2091 		for (i = 0; i < klass->vtable_size; ++i) {
2092 			MonoMethod *cm;
2093 
2094 			cm = klass->vtable [i];
2095 			if (cm) {
2096 				vt->vtable [i] = callbacks.create_jit_trampoline (domain, cm, error);
2097 				if (!is_ok (error)) {
2098 					mono_domain_unlock (domain);
2099 					mono_loader_unlock ();
2100 					return NULL;
2101 				}
2102 			}
2103 		}
2104 	}
2105 
2106 	if (imt_table_bytes) {
2107 		/* Now that the vtable is full, we can actually fill up the IMT */
2108 			for (i = 0; i < MONO_IMT_SIZE; ++i)
2109 				interface_offsets [i] = callbacks.get_imt_trampoline (vt, i);
2110 	}
2111 
2112 	/*
2113 	 * FIXME: Is it ok to allocate while holding the domain/loader locks ? If not, we can release them, allocate, then
2114 	 * re-acquire them and check if another thread has created the vtable in the meantime.
2115 	 */
2116 	/* Special case System.MonoType to avoid infinite recursion */
2117 	if (klass != mono_defaults.runtimetype_class) {
2118 		vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2119 		if (!is_ok (error)) {
2120 			mono_domain_unlock (domain);
2121 			mono_loader_unlock ();
2122 			return NULL;
2123 		}
2124 
2125 		if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2126 			/* This is unregistered in
2127 			   unregister_vtable_reflection_type() in
2128 			   domain.c. */
2129 			MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2130 	}
2131 
2132 	mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass));
2133 
2134 	/*  class_vtable_array keeps an array of created vtables
2135 	 */
2136 	g_ptr_array_add (domain->class_vtable_array, vt);
2137 	/* klass->runtime_info is protected by the loader lock, both when
2138 	 * it it enlarged and when it is stored info.
2139 	 */
2140 
2141 	/*
2142 	 * Store the vtable in klass->runtime_info.
2143 	 * klass->runtime_info is accessed without locking, so this do this last after the vtable has been constructed.
2144 	 */
2145 	mono_memory_barrier ();
2146 
2147 	old_info = klass->runtime_info;
2148 	if (old_info && old_info->max_domain >= domain->domain_id) {
2149 		/* someone already created a large enough runtime info */
2150 		old_info->domain_vtables [domain->domain_id] = vt;
2151 	} else {
2152 		int new_size = domain->domain_id;
2153 		if (old_info)
2154 			new_size = MAX (new_size, old_info->max_domain);
2155 		new_size++;
2156 		/* make the new size a power of two */
2157 		i = 2;
2158 		while (new_size > i)
2159 			i <<= 1;
2160 		new_size = i;
2161 		/* this is a bounded memory retention issue: may want to
2162 		 * handle it differently when we'll have a rcu-like system.
2163 		 */
2164 		runtime_info = (MonoClassRuntimeInfo *)mono_image_alloc0 (klass->image, MONO_SIZEOF_CLASS_RUNTIME_INFO + new_size * sizeof (gpointer));
2165 		runtime_info->max_domain = new_size - 1;
2166 		/* copy the stuff from the older info */
2167 		if (old_info) {
2168 			memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
2169 		}
2170 		runtime_info->domain_vtables [domain->domain_id] = vt;
2171 		/* keep this last*/
2172 		mono_memory_barrier ();
2173 		klass->runtime_info = runtime_info;
2174 	}
2175 
2176 	if (klass == mono_defaults.runtimetype_class) {
2177 		vt->type = mono_type_get_object_checked (domain, &klass->byval_arg, error);
2178 		if (!is_ok (error)) {
2179 			mono_domain_unlock (domain);
2180 			mono_loader_unlock ();
2181 			return NULL;
2182 		}
2183 
2184 		if (mono_object_get_class ((MonoObject *)vt->type) != mono_defaults.runtimetype_class)
2185 			/* This is unregistered in
2186 			   unregister_vtable_reflection_type() in
2187 			   domain.c. */
2188 			MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type");
2189 	}
2190 
2191 	mono_domain_unlock (domain);
2192 	mono_loader_unlock ();
2193 
2194 	/* make sure the parent is initialized */
2195 	/*FIXME shouldn't this fail the current type?*/
2196 	if (klass->parent)
2197 		mono_class_vtable_full (domain, klass->parent, error);
2198 
2199 	return vt;
2200 }
2201 
2202 #ifndef DISABLE_REMOTING
2203 /**
2204  * mono_remote_class_is_interface_proxy:
2205  * \param remote_class
2206  *
2207  * Returns TRUE if the given remote class is a proxying an interface (as
2208  * opposed to a class deriving from MarshalByRefObject).
2209  */
2210 gboolean
mono_remote_class_is_interface_proxy(MonoRemoteClass * remote_class)2211 mono_remote_class_is_interface_proxy (MonoRemoteClass *remote_class)
2212 {
2213 	/* This if condition is taking advantage of how mono_remote_class ()
2214 	 * works: if that code changes, this needs to change too. */
2215 	return (remote_class->interface_count >= 1 &&
2216 		remote_class->proxy_class == mono_defaults.marshalbyrefobject_class);
2217 }
2218 
2219 /**
2220  * mono_class_proxy_vtable:
2221  * \param domain the application domain
2222  * \param remove_class the remote class
2223  * \param error set on error
2224  * Creates a vtable for transparent proxies. It is basically
2225  * a copy of the real vtable of the class wrapped in \p remote_class,
2226  * but all function pointers invoke the remoting functions, and
2227  * \c vtable->klass points to the transparent proxy class, and not to \p class.
2228  *
2229  * On failure returns NULL and sets \p error
2230  */
2231 static MonoVTable *
mono_class_proxy_vtable(MonoDomain * domain,MonoRemoteClass * remote_class,MonoRemotingTarget target_type,MonoError * error)2232 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type, MonoError *error)
2233 {
2234 	MONO_REQ_GC_UNSAFE_MODE;
2235 
2236 	MonoVTable *vt, *pvt;
2237 	int i, j, vtsize, extra_interface_vtsize = 0;
2238 	guint32 max_interface_id;
2239 	MonoClass *k;
2240 	GSList *extra_interfaces = NULL;
2241 	MonoClass *klass = remote_class->proxy_class;
2242 	gpointer *interface_offsets;
2243 	uint8_t *bitmap = NULL;
2244 	int bsize;
2245 	size_t imt_table_bytes;
2246 
2247 #ifdef COMPRESSED_INTERFACE_BITMAP
2248 	int bcsize;
2249 #endif
2250 
2251 	error_init (error);
2252 
2253 	vt = mono_class_vtable (domain, klass);
2254 	g_assert (vt); /*FIXME property handle failure*/
2255 	max_interface_id = vt->max_interface_id;
2256 
2257 	/* Calculate vtable space for extra interfaces */
2258 	for (j = 0; j < remote_class->interface_count; j++) {
2259 		MonoClass* iclass = remote_class->interfaces[j];
2260 		GPtrArray *ifaces;
2261 		int method_count;
2262 
2263 		/*FIXME test for interfaces with variant generic arguments*/
2264 		if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, iclass->interface_id))
2265 			continue;	/* interface implemented by the class */
2266 		if (g_slist_find (extra_interfaces, iclass))
2267 			continue;
2268 
2269 		extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
2270 
2271 		method_count = mono_class_num_methods (iclass);
2272 
2273 		ifaces = mono_class_get_implemented_interfaces (iclass, error);
2274 		goto_if_nok (error, failure);
2275 		if (ifaces) {
2276 			for (i = 0; i < ifaces->len; ++i) {
2277 				MonoClass *ic = (MonoClass *)g_ptr_array_index (ifaces, i);
2278 				/*FIXME test for interfaces with variant generic arguments*/
2279 				if (MONO_CLASS_IMPLEMENTS_INTERFACE (klass, ic->interface_id))
2280 					continue;	/* interface implemented by the class */
2281 				if (g_slist_find (extra_interfaces, ic))
2282 					continue;
2283 				extra_interfaces = g_slist_prepend (extra_interfaces, ic);
2284 				method_count += mono_class_num_methods (ic);
2285 			}
2286 			g_ptr_array_free (ifaces, TRUE);
2287 			ifaces = NULL;
2288 		}
2289 
2290 		extra_interface_vtsize += method_count * sizeof (gpointer);
2291 		if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
2292 	}
2293 
2294 	imt_table_bytes = sizeof (gpointer) * MONO_IMT_SIZE;
2295 	UnlockedIncrement (&mono_stats.imt_number_of_tables);
2296 	UnlockedAdd (&mono_stats.imt_tables_size, imt_table_bytes);
2297 
2298 	vtsize = imt_table_bytes + MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer);
2299 
2300 	UnlockedAdd (&mono_stats.class_vtable_size, vtsize + extra_interface_vtsize);
2301 
2302 	interface_offsets = alloc_vtable (domain, vtsize + extra_interface_vtsize, imt_table_bytes);
2303 	pvt = (MonoVTable*) ((char*)interface_offsets + imt_table_bytes);
2304 	g_assert (!((gsize)pvt & 7));
2305 
2306 	memcpy (pvt, vt, MONO_SIZEOF_VTABLE + klass->vtable_size * sizeof (gpointer));
2307 
2308 	pvt->klass = mono_defaults.transparent_proxy_class;
2309 	/* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
2310 	pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
2311 
2312 	if (mono_remote_class_is_interface_proxy (remote_class)) {
2313 		/* If it's a transparent proxy for an interface, set the
2314 		 * MonoVTable:type to the interface type, not the placeholder
2315 		 * MarshalByRefObject class.  This is used when mini JITs calls
2316 		 * to Object.GetType ()
2317 		 */
2318 		MonoType *itf_proxy_type = &remote_class->interfaces[0]->byval_arg;
2319 		pvt->type = mono_type_get_object_checked (domain, itf_proxy_type, error);
2320 		goto_if_nok (error, failure);
2321 	}
2322 
2323 	/* initialize vtable */
2324 	mono_class_setup_vtable (klass);
2325 	for (i = 0; i < klass->vtable_size; ++i) {
2326 		MonoMethod *cm;
2327 
2328 		if ((cm = klass->vtable [i])) {
2329 			pvt->vtable [i] = create_remoting_trampoline (domain, cm, target_type, error);
2330 			goto_if_nok (error, failure);
2331 		} else
2332 			pvt->vtable [i] = NULL;
2333 	}
2334 
2335 	if (mono_class_is_abstract (klass)) {
2336 		/* create trampolines for abstract methods */
2337 		for (k = klass; k; k = k->parent) {
2338 			MonoMethod* m;
2339 			gpointer iter = NULL;
2340 			while ((m = mono_class_get_methods (k, &iter)))
2341 				if (!pvt->vtable [m->slot]) {
2342 					pvt->vtable [m->slot] = create_remoting_trampoline (domain, m, target_type, error);
2343 					goto_if_nok (error, failure);
2344 				}
2345 		}
2346 	}
2347 
2348 	pvt->max_interface_id = max_interface_id;
2349 	bsize = sizeof (guint8) * (max_interface_id/8 + 1 );
2350 #ifdef COMPRESSED_INTERFACE_BITMAP
2351 	bitmap = (uint8_t *)g_malloc0 (bsize);
2352 #else
2353 	bitmap = (uint8_t *)mono_domain_alloc0 (domain, bsize);
2354 #endif
2355 
2356 	for (i = 0; i < klass->interface_offsets_count; ++i) {
2357 		int interface_id = klass->interfaces_packed [i]->interface_id;
2358 		bitmap [interface_id >> 3] |= (1 << (interface_id & 7));
2359 	}
2360 
2361 	if (extra_interfaces) {
2362 		int slot = klass->vtable_size;
2363 		MonoClass* interf;
2364 		gpointer iter;
2365 		MonoMethod* cm;
2366 		GSList *list_item;
2367 
2368 		/* Create trampolines for the methods of the interfaces */
2369 		for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
2370 			interf = (MonoClass *)list_item->data;
2371 
2372 			bitmap [interf->interface_id >> 3] |= (1 << (interf->interface_id & 7));
2373 
2374 			iter = NULL;
2375 			j = 0;
2376 			while ((cm = mono_class_get_methods (interf, &iter))) {
2377 				pvt->vtable [slot + j++] = create_remoting_trampoline (domain, cm, target_type, error);
2378 				goto_if_nok (error, failure);
2379 			}
2380 
2381 			slot += mono_class_num_methods (interf);
2382 		}
2383 	}
2384 
2385 	/* Now that the vtable is full, we can actually fill up the IMT */
2386 	build_imt (klass, pvt, domain, interface_offsets, extra_interfaces);
2387 	if (extra_interfaces) {
2388 		g_slist_free (extra_interfaces);
2389 	}
2390 
2391 #ifdef COMPRESSED_INTERFACE_BITMAP
2392 	bcsize = mono_compress_bitmap (NULL, bitmap, bsize);
2393 	pvt->interface_bitmap = mono_domain_alloc0 (domain, bcsize);
2394 	mono_compress_bitmap (pvt->interface_bitmap, bitmap, bsize);
2395 	g_free (bitmap);
2396 #else
2397 	pvt->interface_bitmap = bitmap;
2398 #endif
2399 	return pvt;
2400 failure:
2401 	if (extra_interfaces)
2402 		g_slist_free (extra_interfaces);
2403 #ifdef COMPRESSED_INTERFACE_BITMAP
2404 	g_free (bitmap);
2405 #endif
2406 	return NULL;
2407 }
2408 
2409 #endif /* DISABLE_REMOTING */
2410 
2411 /**
2412  * mono_class_field_is_special_static:
2413  * \returns whether \p field is a thread/context static field.
2414  */
2415 gboolean
mono_class_field_is_special_static(MonoClassField * field)2416 mono_class_field_is_special_static (MonoClassField *field)
2417 {
2418 	MONO_REQ_GC_NEUTRAL_MODE
2419 
2420 	if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2421 		return FALSE;
2422 	if (mono_field_is_deleted (field))
2423 		return FALSE;
2424 	if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
2425 		if (field_is_special_static (field->parent, field) != SPECIAL_STATIC_NONE)
2426 			return TRUE;
2427 	}
2428 	return FALSE;
2429 }
2430 
2431 /**
2432  * mono_class_field_get_special_static_type:
2433  * \param field The \c MonoClassField describing the field.
2434  * \returns \c SPECIAL_STATIC_THREAD if the field is thread static, \c SPECIAL_STATIC_CONTEXT if it is context static,
2435  * \c SPECIAL_STATIC_NONE otherwise.
2436  */
2437 guint32
mono_class_field_get_special_static_type(MonoClassField * field)2438 mono_class_field_get_special_static_type (MonoClassField *field)
2439 {
2440 	MONO_REQ_GC_NEUTRAL_MODE
2441 
2442 	if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
2443 		return SPECIAL_STATIC_NONE;
2444 	if (mono_field_is_deleted (field))
2445 		return SPECIAL_STATIC_NONE;
2446 	if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
2447 		return field_is_special_static (field->parent, field);
2448 	return SPECIAL_STATIC_NONE;
2449 }
2450 
2451 /**
2452  * mono_class_has_special_static_fields:
2453  * \returns whether \p klass has any thread/context static fields.
2454  */
2455 gboolean
mono_class_has_special_static_fields(MonoClass * klass)2456 mono_class_has_special_static_fields (MonoClass *klass)
2457 {
2458 	MONO_REQ_GC_NEUTRAL_MODE
2459 
2460 	MonoClassField *field;
2461 	gpointer iter;
2462 
2463 	iter = NULL;
2464 	while ((field = mono_class_get_fields (klass, &iter))) {
2465 		g_assert (field->parent == klass);
2466 		if (mono_class_field_is_special_static (field))
2467 			return TRUE;
2468 	}
2469 
2470 	return FALSE;
2471 }
2472 
2473 #ifndef DISABLE_REMOTING
2474 /**
2475  * create_remote_class_key:
2476  * Creates an array of pointers that can be used as a hash key for a remote class.
2477  * The first element of the array is the number of pointers.
2478  */
2479 static gpointer*
create_remote_class_key(MonoRemoteClass * remote_class,MonoClass * extra_class)2480 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
2481 {
2482 	MONO_REQ_GC_NEUTRAL_MODE;
2483 
2484 	gpointer *key;
2485 	int i, j;
2486 
2487 	if (remote_class == NULL) {
2488 		if (mono_class_is_interface (extra_class)) {
2489 			key = (void **)g_malloc (sizeof(gpointer) * 3);
2490 			key [0] = GINT_TO_POINTER (2);
2491 			key [1] = mono_defaults.marshalbyrefobject_class;
2492 			key [2] = extra_class;
2493 		} else {
2494 			key = (void **)g_malloc (sizeof(gpointer) * 2);
2495 			key [0] = GINT_TO_POINTER (1);
2496 			key [1] = extra_class;
2497 		}
2498 	} else {
2499 		if (extra_class != NULL && mono_class_is_interface (extra_class)) {
2500 			key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
2501 			key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
2502 			key [1] = remote_class->proxy_class;
2503 
2504 			// Keep the list of interfaces sorted
2505 			for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
2506 				if (extra_class && remote_class->interfaces [i] > extra_class) {
2507 					key [j++] = extra_class;
2508 					extra_class = NULL;
2509 				}
2510 				key [j] = remote_class->interfaces [i];
2511 			}
2512 			if (extra_class)
2513 				key [j] = extra_class;
2514 		} else {
2515 			// Replace the old class. The interface list is the same
2516 			key = (void **)g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
2517 			key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
2518 			key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
2519 			for (i = 0; i < remote_class->interface_count; i++)
2520 				key [2 + i] = remote_class->interfaces [i];
2521 		}
2522 	}
2523 
2524 	return key;
2525 }
2526 
2527 /**
2528  * copy_remote_class_key:
2529  *
2530  *   Make a copy of KEY in the domain and return the copy.
2531  */
2532 static gpointer*
copy_remote_class_key(MonoDomain * domain,gpointer * key)2533 copy_remote_class_key (MonoDomain *domain, gpointer *key)
2534 {
2535 	MONO_REQ_GC_NEUTRAL_MODE
2536 
2537 	int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
2538 	gpointer *mp_key = (gpointer *)mono_domain_alloc (domain, key_size);
2539 
2540 	memcpy (mp_key, key, key_size);
2541 
2542 	return mp_key;
2543 }
2544 
2545 /**
2546  * mono_remote_class:
2547  * \param domain the application domain
2548  * \param class_name name of the remote class
2549  * \param error set on error
2550  * Creates and initializes a \c MonoRemoteClass object for a remote type.
2551  * On failure returns NULL and sets \p error
2552  */
2553 MonoRemoteClass*
mono_remote_class(MonoDomain * domain,MonoStringHandle class_name,MonoClass * proxy_class,MonoError * error)2554 mono_remote_class (MonoDomain *domain, MonoStringHandle class_name, MonoClass *proxy_class, MonoError *error)
2555 {
2556 	MONO_REQ_GC_UNSAFE_MODE;
2557 
2558 	MonoRemoteClass *rc;
2559 	gpointer* key, *mp_key;
2560 	char *name;
2561 
2562 	error_init (error);
2563 
2564 	key = create_remote_class_key (NULL, proxy_class);
2565 
2566 	mono_domain_lock (domain);
2567 	rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2568 
2569 	if (rc) {
2570 		g_free (key);
2571 		mono_domain_unlock (domain);
2572 		return rc;
2573 	}
2574 
2575 	name = mono_string_to_utf8_mp (domain->mp, MONO_HANDLE_RAW (class_name), error);
2576 	if (!is_ok (error)) {
2577 		g_free (key);
2578 		mono_domain_unlock (domain);
2579 		return NULL;
2580 	}
2581 
2582 	mp_key = copy_remote_class_key (domain, key);
2583 	g_free (key);
2584 	key = mp_key;
2585 
2586 	if (mono_class_is_interface (proxy_class)) {
2587 		/* If we need to proxy an interface, we use this stylized
2588 		 * representation (interface_count >= 1, proxy_class is
2589 		 * MarshalByRefObject).  The code in
2590 		 * mono_remote_class_is_interface_proxy () depends on being
2591 		 * able to detect that we're doing this, so if this
2592 		 * representation changes, change GetType, too. */
2593 		rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*));
2594 		rc->interface_count = 1;
2595 		rc->interfaces [0] = proxy_class;
2596 		rc->proxy_class = mono_defaults.marshalbyrefobject_class;
2597 	} else {
2598 		rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS);
2599 		rc->interface_count = 0;
2600 		rc->proxy_class = proxy_class;
2601 	}
2602 
2603 	rc->default_vtable = NULL;
2604 	rc->xdomain_vtable = NULL;
2605 	rc->proxy_class_name = name;
2606 #ifndef DISABLE_PERFCOUNTERS
2607 	mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, mono_string_length (MONO_HANDLE_RAW (class_name)) + 1);
2608 #endif
2609 
2610 	g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2611 
2612 	mono_domain_unlock (domain);
2613 	return rc;
2614 }
2615 
2616 /**
2617  * clone_remote_class:
2618  * Creates a copy of the remote_class, adding the provided class or interface
2619  */
2620 static MonoRemoteClass*
clone_remote_class(MonoDomain * domain,MonoRemoteClass * remote_class,MonoClass * extra_class)2621 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
2622 {
2623 	MONO_REQ_GC_NEUTRAL_MODE;
2624 
2625 	MonoRemoteClass *rc;
2626 	gpointer* key, *mp_key;
2627 
2628 	key = create_remote_class_key (remote_class, extra_class);
2629 	rc = (MonoRemoteClass *)g_hash_table_lookup (domain->proxy_vtable_hash, key);
2630 	if (rc != NULL) {
2631 		g_free (key);
2632 		return rc;
2633 	}
2634 
2635 	mp_key = copy_remote_class_key (domain, key);
2636 	g_free (key);
2637 	key = mp_key;
2638 
2639 	if (mono_class_is_interface (extra_class)) {
2640 		int i,j;
2641 		rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * (remote_class->interface_count + 1));
2642 		rc->proxy_class = remote_class->proxy_class;
2643 		rc->interface_count = remote_class->interface_count + 1;
2644 
2645 		// Keep the list of interfaces sorted, since the hash key of
2646 		// the remote class depends on this
2647 		for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
2648 			if (remote_class->interfaces [i] > extra_class && i == j)
2649 				rc->interfaces [j++] = extra_class;
2650 			rc->interfaces [j] = remote_class->interfaces [i];
2651 		}
2652 		if (i == j)
2653 			rc->interfaces [j] = extra_class;
2654 	} else {
2655 		// Replace the old class. The interface array is the same
2656 		rc = (MonoRemoteClass *)mono_domain_alloc (domain, MONO_SIZEOF_REMOTE_CLASS + sizeof(MonoClass*) * remote_class->interface_count);
2657 		rc->proxy_class = extra_class;
2658 		rc->interface_count = remote_class->interface_count;
2659 		if (rc->interface_count > 0)
2660 			memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
2661 	}
2662 
2663 	rc->default_vtable = NULL;
2664 	rc->xdomain_vtable = NULL;
2665 	rc->proxy_class_name = remote_class->proxy_class_name;
2666 
2667 	g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
2668 
2669 	return rc;
2670 }
2671 
2672 gpointer
mono_remote_class_vtable(MonoDomain * domain,MonoRemoteClass * remote_class,MonoRealProxyHandle rp,MonoError * error)2673 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxyHandle rp, MonoError *error)
2674 {
2675 	MONO_REQ_GC_UNSAFE_MODE;
2676 
2677 	error_init (error);
2678 
2679 	mono_loader_lock (); /*FIXME mono_class_from_mono_type and mono_class_proxy_vtable take it*/
2680 	mono_domain_lock (domain);
2681 	gint32 target_domain_id = MONO_HANDLE_GETVAL (rp, target_domain_id);
2682 	if (target_domain_id != -1) {
2683 		if (remote_class->xdomain_vtable == NULL)
2684 			remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN, error);
2685 		mono_domain_unlock (domain);
2686 		mono_loader_unlock ();
2687 		return_val_if_nok (error, NULL);
2688 		return remote_class->xdomain_vtable;
2689 	}
2690 	if (remote_class->default_vtable == NULL) {
2691 		MonoReflectionTypeHandle reftype = MONO_HANDLE_NEW (MonoReflectionType, NULL);
2692 		MONO_HANDLE_GET (reftype, rp, class_to_proxy);
2693 
2694 		MonoType *type = MONO_HANDLE_GETVAL (reftype, type);
2695 		MonoClass *klass = mono_class_from_mono_type (type);
2696 #ifndef DISABLE_COM
2697 		if ((mono_class_is_com_object (klass) || (mono_class_get_com_object_class () && klass == mono_class_get_com_object_class ())) && !mono_vtable_is_remote (mono_class_vtable (mono_domain_get (), klass)))
2698 			remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP, error);
2699 		else
2700 #endif
2701 			remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN, error);
2702 		/* N.B. both branches of the if modify error */
2703 		if (!is_ok (error)) {
2704 			mono_domain_unlock (domain);
2705 			mono_loader_unlock ();
2706 			return NULL;
2707 		}
2708 	}
2709 
2710 	mono_domain_unlock (domain);
2711 	mono_loader_unlock ();
2712 	return remote_class->default_vtable;
2713 }
2714 
2715 /**
2716  * mono_upgrade_remote_class:
2717  * \param domain the application domain
2718  * \param tproxy the proxy whose remote class has to be upgraded.
2719  * \param klass class to which the remote class can be casted.
2720  * \param error set on error
2721  * Updates the vtable of the remote class by adding the necessary method slots
2722  * and interface offsets so it can be safely casted to klass. klass can be a
2723  * class or an interface.  On success returns TRUE, on failure returns FALSE and sets \p error.
2724  */
2725 gboolean
mono_upgrade_remote_class(MonoDomain * domain,MonoObjectHandle proxy_object,MonoClass * klass,MonoError * error)2726 mono_upgrade_remote_class (MonoDomain *domain, MonoObjectHandle proxy_object, MonoClass *klass, MonoError *error)
2727 {
2728 	MONO_REQ_GC_UNSAFE_MODE;
2729 
2730 	error_init (error);
2731 
2732 	MonoTransparentProxyHandle tproxy = MONO_HANDLE_CAST (MonoTransparentProxy, proxy_object);
2733 	MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (tproxy, remote_class);
2734 
2735 	gboolean redo_vtable;
2736 	if (mono_class_is_interface (klass)) {
2737 		int i;
2738 		redo_vtable = TRUE;
2739 		for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2740 			if (remote_class->interfaces [i] == klass)
2741 				redo_vtable = FALSE;
2742 	}
2743 	else {
2744 		redo_vtable = (remote_class->proxy_class != klass);
2745 	}
2746 
2747 	mono_loader_lock (); /*FIXME mono_remote_class_vtable requires it.*/
2748 	mono_domain_lock (domain);
2749 	if (redo_vtable) {
2750 		MonoRemoteClass *fresh_remote_class = clone_remote_class (domain, remote_class, klass);
2751 		MONO_HANDLE_SETVAL (tproxy, remote_class, MonoRemoteClass*, fresh_remote_class);
2752 		MonoRealProxyHandle real_proxy = MONO_HANDLE_NEW (MonoRealProxy, NULL);
2753 		MONO_HANDLE_GET (real_proxy, tproxy, rp);
2754 		MONO_HANDLE_SETVAL (proxy_object, vtable, MonoVTable*, mono_remote_class_vtable (domain, fresh_remote_class, real_proxy, error));
2755 		goto_if_nok (error, leave);
2756 	}
2757 
2758 leave:
2759 	mono_domain_unlock (domain);
2760 	mono_loader_unlock ();
2761 	return is_ok (error);
2762 }
2763 #endif /* DISABLE_REMOTING */
2764 
2765 
2766 /**
2767  * mono_object_get_virtual_method:
2768  * \param obj object to operate on.
2769  * \param method method
2770  * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2771  * the instance of a callvirt of \p method.
2772  */
2773 MonoMethod*
mono_object_get_virtual_method(MonoObject * obj_raw,MonoMethod * method)2774 mono_object_get_virtual_method (MonoObject *obj_raw, MonoMethod *method)
2775 {
2776 	MONO_REQ_GC_UNSAFE_MODE;
2777 	HANDLE_FUNCTION_ENTER ();
2778 	MonoError error;
2779 	MONO_HANDLE_DCL (MonoObject, obj);
2780 	MonoMethod *result = mono_object_handle_get_virtual_method (obj, method, &error);
2781 	mono_error_assert_ok (&error);
2782 	HANDLE_FUNCTION_RETURN_VAL (result);
2783 }
2784 
2785 /**
2786  * mono_object_handle_get_virtual_method:
2787  * \param obj object to operate on.
2788  * \param method method
2789  * Retrieves the \c MonoMethod that would be called on \p obj if \p obj is passed as
2790  * the instance of a callvirt of \p method.
2791  */
2792 MonoMethod*
mono_object_handle_get_virtual_method(MonoObjectHandle obj,MonoMethod * method,MonoError * error)2793 mono_object_handle_get_virtual_method (MonoObjectHandle obj, MonoMethod *method, MonoError *error)
2794 {
2795 	error_init (error);
2796 
2797 	gboolean is_proxy = FALSE;
2798 	MonoClass *klass = mono_handle_class (obj);
2799 	if (mono_class_is_transparent_proxy (klass)) {
2800 		MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
2801 		klass = remote_class->proxy_class;
2802 		is_proxy = TRUE;
2803 	}
2804 	return class_get_virtual_method (klass, method, is_proxy, error);
2805 }
2806 
2807 static MonoMethod*
class_get_virtual_method(MonoClass * klass,MonoMethod * method,gboolean is_proxy,MonoError * error)2808 class_get_virtual_method (MonoClass *klass, MonoMethod *method, gboolean is_proxy, MonoError *error)
2809 {
2810 	error_init (error);
2811 
2812 
2813 	if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2814 			return method;
2815 
2816 	mono_class_setup_vtable (klass);
2817 	MonoMethod **vtable = klass->vtable;
2818 
2819 	if (method->slot == -1) {
2820 		/* method->slot might not be set for instances of generic methods */
2821 		if (method->is_inflated) {
2822 			g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2823 			method->slot = ((MonoMethodInflated*)method)->declaring->slot;
2824 		} else {
2825 			if (!is_proxy)
2826 				g_assert_not_reached ();
2827 		}
2828 	}
2829 
2830 	MonoMethod *res = NULL;
2831 	/* check method->slot is a valid index: perform isinstance? */
2832 	if (method->slot != -1) {
2833 		if (mono_class_is_interface (method->klass)) {
2834 			if (!is_proxy) {
2835 				gboolean variance_used = FALSE;
2836 				int iface_offset = mono_class_interface_offset_with_variance (klass, method->klass, &variance_used);
2837 				g_assert (iface_offset > 0);
2838 				res = vtable [iface_offset + method->slot];
2839 			}
2840 		} else {
2841 			res = vtable [method->slot];
2842 		}
2843     }
2844 
2845 #ifndef DISABLE_REMOTING
2846 	if (is_proxy) {
2847 		/* It may be an interface, abstract class method or generic method */
2848 		if (!res || mono_method_signature (res)->generic_param_count)
2849 			res = method;
2850 
2851 		/* generic methods demand invoke_with_check */
2852 		if (mono_method_signature (res)->generic_param_count)
2853 			res = mono_marshal_get_remoting_invoke_with_check (res);
2854 		else {
2855 #ifndef DISABLE_COM
2856 			if (klass == mono_class_get_com_object_class () || mono_class_is_com_object (klass))
2857 				res = mono_cominterop_get_invoke (res);
2858 			else
2859 #endif
2860 				res = mono_marshal_get_remoting_invoke (res);
2861 		}
2862 	} else
2863 #endif
2864 	{
2865 		if (method->is_inflated) {
2866 			/* Have to inflate the result */
2867 			res = mono_class_inflate_generic_method_checked (res, &((MonoMethodInflated*)method)->context, error);
2868 		}
2869 	}
2870 
2871 	return res;
2872 }
2873 
2874 static MonoObject*
do_runtime_invoke(MonoMethod * method,void * obj,void ** params,MonoObject ** exc,MonoError * error)2875 do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
2876 {
2877 	MONO_REQ_GC_UNSAFE_MODE;
2878 
2879 	MonoObject *result = NULL;
2880 
2881 	g_assert (callbacks.runtime_invoke);
2882 
2883 	error_init (error);
2884 
2885 	MONO_PROFILER_RAISE (method_begin_invoke, (method));
2886 
2887 	result = callbacks.runtime_invoke (method, obj, params, exc, error);
2888 
2889 	MONO_PROFILER_RAISE (method_end_invoke, (method));
2890 
2891 	if (!mono_error_ok (error))
2892 		return NULL;
2893 
2894 	return result;
2895 }
2896 
2897 /**
2898  * mono_runtime_invoke:
2899  * \param method method to invoke
2900  * \param obj object instance
2901  * \param params arguments to the method
2902  * \param exc exception information.
2903  * Invokes the method represented by \p method on the object \p obj.
2904  * \p obj is the \c this pointer, it should be NULL for static
2905  * methods, a \c MonoObject* for object instances and a pointer to
2906  * the value type for value types.
2907  *
2908  * The params array contains the arguments to the method with the
2909  * same convention: \c MonoObject* pointers for object instances and
2910  * pointers to the value type otherwise.
2911  *
2912  * From unmanaged code you'll usually use the
2913  * \c mono_runtime_invoke variant.
2914  *
2915  * Note that this function doesn't handle virtual methods for
2916  * you, it will exec the exact method you pass: we still need to
2917  * expose a function to lookup the derived class implementation
2918  * of a virtual method (there are examples of this in the code,
2919  * though).
2920  *
2921  * You can pass NULL as the \p exc argument if you don't want to
2922  * catch exceptions, otherwise, \c *exc will be set to the exception
2923  * thrown, if any.  if an exception is thrown, you can't use the
2924  * \c MonoObject* result from the function.
2925  *
2926  * If the method returns a value type, it is boxed in an object
2927  * reference.
2928  */
2929 MonoObject*
mono_runtime_invoke(MonoMethod * method,void * obj,void ** params,MonoObject ** exc)2930 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2931 {
2932 	MonoError error;
2933 	MonoObject *res;
2934 	if (exc) {
2935 		res = mono_runtime_try_invoke (method, obj, params, exc, &error);
2936 		if (*exc == NULL && !mono_error_ok(&error)) {
2937 			*exc = (MonoObject*) mono_error_convert_to_exception (&error);
2938 		} else
2939 			mono_error_cleanup (&error);
2940 	} else {
2941 		res = mono_runtime_invoke_checked (method, obj, params, &error);
2942 		mono_error_raise_exception_deprecated (&error); /* OK to throw, external only without a good alternative */
2943 	}
2944 	return res;
2945 }
2946 
2947 /**
2948  * mono_runtime_try_invoke:
2949  * \param method method to invoke
2950  * \param obj object instance
2951  * \param params arguments to the method
2952  * \param exc exception information.
2953  * \param error set on error
2954  * Invokes the method represented by \p method on the object \p obj.
2955  *
2956  * \p obj is the \c this pointer, it should be NULL for static
2957  * methods, a \c MonoObject* for object instances and a pointer to
2958  * the value type for value types.
2959  *
2960  * The params array contains the arguments to the method with the
2961  * same convention: \c MonoObject* pointers for object instances and
2962  * pointers to the value type otherwise.
2963  *
2964  * From unmanaged code you'll usually use the
2965  * mono_runtime_invoke() variant.
2966  *
2967  * Note that this function doesn't handle virtual methods for
2968  * you, it will exec the exact method you pass: we still need to
2969  * expose a function to lookup the derived class implementation
2970  * of a virtual method (there are examples of this in the code,
2971  * though).
2972  *
2973  * For this function, you must not pass NULL as the \p exc argument if
2974  * you don't want to catch exceptions, use
2975  * mono_runtime_invoke_checked().  If an exception is thrown, you
2976  * can't use the \c MonoObject* result from the function.
2977  *
2978  * If this method cannot be invoked, \p error will be set and \p exc and
2979  * the return value must not be used.
2980  *
2981  * If the method returns a value type, it is boxed in an object
2982  * reference.
2983  */
2984 MonoObject*
mono_runtime_try_invoke(MonoMethod * method,void * obj,void ** params,MonoObject ** exc,MonoError * error)2985 mono_runtime_try_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError* error)
2986 {
2987 	MONO_REQ_GC_UNSAFE_MODE;
2988 
2989 	g_assert (exc != NULL);
2990 
2991 	if (mono_runtime_get_no_exec ())
2992 		g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2993 
2994 	return do_runtime_invoke (method, obj, params, exc, error);
2995 }
2996 
2997 /**
2998  * mono_runtime_invoke_checked:
2999  * \param method method to invoke
3000  * \param obj object instance
3001  * \param params arguments to the method
3002  * \param error set on error
3003  * Invokes the method represented by \p method on the object \p obj.
3004  *
3005  * \p obj is the \c this pointer, it should be NULL for static
3006  * methods, a \c MonoObject* for object instances and a pointer to
3007  * the value type for value types.
3008  *
3009  * The \p params array contains the arguments to the method with the
3010  * same convention: \c MonoObject* pointers for object instances and
3011  * pointers to the value type otherwise.
3012  *
3013  * From unmanaged code you'll usually use the
3014  * mono_runtime_invoke() variant.
3015  *
3016  * Note that this function doesn't handle virtual methods for
3017  * you, it will exec the exact method you pass: we still need to
3018  * expose a function to lookup the derived class implementation
3019  * of a virtual method (there are examples of this in the code,
3020  * though).
3021  *
3022  * If an exception is thrown, you can't use the \c MonoObject* result
3023  * from the function.
3024  *
3025  * If this method cannot be invoked, \p error will be set.  If the
3026  * method throws an exception (and we're in coop mode) the exception
3027  * will be set in \p error.
3028  *
3029  * If the method returns a value type, it is boxed in an object
3030  * reference.
3031  */
3032 MonoObject*
mono_runtime_invoke_checked(MonoMethod * method,void * obj,void ** params,MonoError * error)3033 mono_runtime_invoke_checked (MonoMethod *method, void *obj, void **params, MonoError* error)
3034 {
3035 	MONO_REQ_GC_UNSAFE_MODE;
3036 
3037 	if (mono_runtime_get_no_exec ())
3038 		g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
3039 
3040 	return do_runtime_invoke (method, obj, params, NULL, error);
3041 }
3042 
3043 /**
3044  * mono_method_get_unmanaged_thunk:
3045  * \param method method to generate a thunk for.
3046  *
3047  * Returns an \c unmanaged->managed thunk that can be used to call
3048  * a managed method directly from C.
3049  *
3050  * The thunk's C signature closely matches the managed signature:
3051  *
3052  * C#: <code>public bool Equals (object obj);</code>
3053  *
3054  * C:  <code>typedef MonoBoolean (*Equals)(MonoObject*, MonoObject*, MonoException**);</code>
3055  *
3056  * The 1st (<code>this</code>) parameter must not be used with static methods:
3057  *
3058  * C#: <code>public static bool ReferenceEquals (object a, object b);</code>
3059  *
3060  * C:  <code>typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*, MonoException**);</code>
3061  *
3062  * The last argument must be a non-null \c MonoException* pointer.
3063  * It has "out" semantics. After invoking the thunk, \c *ex will be NULL if no
3064  * exception has been thrown in managed code. Otherwise it will point
3065  * to the \c MonoException* caught by the thunk. In this case, the result of
3066  * the thunk is undefined:
3067  *
3068  * <pre>
3069  * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
3070  *
3071  * MonoException *ex = NULL;
3072  *
3073  * Equals func = mono_method_get_unmanaged_thunk (method);
3074  *
3075  * MonoBoolean res = func (thisObj, objToCompare, &ex);
3076  *
3077  * if (ex) {
3078  *
3079  *    // handle exception
3080  *
3081  * }
3082  * </pre>
3083  *
3084  * The calling convention of the thunk matches the platform's default
3085  * convention. This means that under Windows, C declarations must
3086  * contain the \c __stdcall attribute:
3087  *
3088  * C: <code>typedef MonoBoolean (__stdcall *Equals)(MonoObject*, MonoObject*, MonoException**);</code>
3089  *
3090  * LIMITATIONS
3091  *
3092  * Value type arguments and return values are treated as they were objects:
3093  *
3094  * C#: <code>public static Rectangle Intersect (Rectangle a, Rectangle b);</code>
3095  * C:  <code>typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);</code>
3096  *
3097  * Arguments must be properly boxed upon trunk's invocation, while return
3098  * values must be unboxed.
3099  */
3100 gpointer
mono_method_get_unmanaged_thunk(MonoMethod * method)3101 mono_method_get_unmanaged_thunk (MonoMethod *method)
3102 {
3103 	MONO_REQ_GC_NEUTRAL_MODE;
3104 	MONO_REQ_API_ENTRYPOINT;
3105 
3106 	MonoError error;
3107 	gpointer res;
3108 
3109 	g_assert (!mono_threads_is_coop_enabled ());
3110 
3111 	MONO_ENTER_GC_UNSAFE;
3112 	method = mono_marshal_get_thunk_invoke_wrapper (method);
3113 	res = mono_compile_method_checked (method, &error);
3114 	mono_error_cleanup (&error);
3115 	MONO_EXIT_GC_UNSAFE;
3116 
3117 	return res;
3118 }
3119 
3120 void
mono_copy_value(MonoType * type,void * dest,void * value,int deref_pointer)3121 mono_copy_value (MonoType *type, void *dest, void *value, int deref_pointer)
3122 {
3123 	MONO_REQ_GC_UNSAFE_MODE;
3124 
3125 	int t;
3126 	if (type->byref) {
3127 		/* object fields cannot be byref, so we don't need a
3128 		   wbarrier here */
3129 		gpointer *p = (gpointer*)dest;
3130 		*p = value;
3131 		return;
3132 	}
3133 	t = type->type;
3134 handle_enum:
3135 	switch (t) {
3136 	case MONO_TYPE_BOOLEAN:
3137 	case MONO_TYPE_I1:
3138 	case MONO_TYPE_U1: {
3139 		guint8 *p = (guint8*)dest;
3140 		*p = value ? *(guint8*)value : 0;
3141 		return;
3142 	}
3143 	case MONO_TYPE_I2:
3144 	case MONO_TYPE_U2:
3145 	case MONO_TYPE_CHAR: {
3146 		guint16 *p = (guint16*)dest;
3147 		*p = value ? *(guint16*)value : 0;
3148 		return;
3149 	}
3150 #if SIZEOF_VOID_P == 4
3151 	case MONO_TYPE_I:
3152 	case MONO_TYPE_U:
3153 #endif
3154 	case MONO_TYPE_I4:
3155 	case MONO_TYPE_U4: {
3156 		gint32 *p = (gint32*)dest;
3157 		*p = value ? *(gint32*)value : 0;
3158 		return;
3159 	}
3160 #if SIZEOF_VOID_P == 8
3161 	case MONO_TYPE_I:
3162 	case MONO_TYPE_U:
3163 #endif
3164 	case MONO_TYPE_I8:
3165 	case MONO_TYPE_U8: {
3166 		gint64 *p = (gint64*)dest;
3167 		*p = value ? *(gint64*)value : 0;
3168 		return;
3169 	}
3170 	case MONO_TYPE_R4: {
3171 		float *p = (float*)dest;
3172 		*p = value ? *(float*)value : 0;
3173 		return;
3174 	}
3175 	case MONO_TYPE_R8: {
3176 		double *p = (double*)dest;
3177 		*p = value ? *(double*)value : 0;
3178 		return;
3179 	}
3180 	case MONO_TYPE_STRING:
3181 	case MONO_TYPE_SZARRAY:
3182 	case MONO_TYPE_CLASS:
3183 	case MONO_TYPE_OBJECT:
3184 	case MONO_TYPE_ARRAY:
3185 		mono_gc_wbarrier_generic_store (dest, deref_pointer ? *(MonoObject **)value : (MonoObject *)value);
3186 		return;
3187 	case MONO_TYPE_FNPTR:
3188 	case MONO_TYPE_PTR: {
3189 		gpointer *p = (gpointer*)dest;
3190 		*p = deref_pointer? *(gpointer*)value: value;
3191 		return;
3192 	}
3193 	case MONO_TYPE_VALUETYPE:
3194 		/* note that 't' and 'type->type' can be different */
3195 		if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
3196 			t = mono_class_enum_basetype (type->data.klass)->type;
3197 			goto handle_enum;
3198 		} else {
3199 			MonoClass *klass = mono_class_from_mono_type (type);
3200 			int size = mono_class_value_size (klass, NULL);
3201 			if (value == NULL)
3202 				mono_gc_bzero_atomic (dest, size);
3203 			else
3204 				mono_gc_wbarrier_value_copy (dest, value, 1, klass);
3205 		}
3206 		return;
3207 	case MONO_TYPE_GENERICINST:
3208 		t = type->data.generic_class->container_class->byval_arg.type;
3209 		goto handle_enum;
3210 	default:
3211 		g_error ("got type %x", type->type);
3212 	}
3213 }
3214 
3215 /**
3216  * mono_field_set_value:
3217  * \param obj Instance object
3218  * \param field \c MonoClassField describing the field to set
3219  * \param value The value to be set
3220  *
3221  * Sets the value of the field described by \p field in the object instance \p obj
3222  * to the value passed in \p value.   This method should only be used for instance
3223  * fields.   For static fields, use \c mono_field_static_set_value.
3224  *
3225  * The value must be in the native format of the field type.
3226  */
3227 void
mono_field_set_value(MonoObject * obj,MonoClassField * field,void * value)3228 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
3229 {
3230 	MONO_REQ_GC_UNSAFE_MODE;
3231 
3232 	void *dest;
3233 
3234 	g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3235 
3236 	dest = (char*)obj + field->offset;
3237 	mono_copy_value (field->type, dest, value, FALSE);
3238 }
3239 
3240 /**
3241  * mono_field_static_set_value:
3242  * \param field \c MonoClassField describing the field to set
3243  * \param value The value to be set
3244  * Sets the value of the static field described by \p field
3245  * to the value passed in \p value.
3246  * The value must be in the native format of the field type.
3247  */
3248 void
mono_field_static_set_value(MonoVTable * vt,MonoClassField * field,void * value)3249 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
3250 {
3251 	MONO_REQ_GC_UNSAFE_MODE;
3252 
3253 	void *dest;
3254 
3255 	g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3256 	/* you cant set a constant! */
3257 	g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
3258 
3259 	if (field->offset == -1) {
3260 		/* Special static */
3261 		gpointer addr;
3262 
3263 		mono_domain_lock (vt->domain);
3264 		addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3265 		mono_domain_unlock (vt->domain);
3266 		dest = mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3267 	} else {
3268 		dest = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3269 	}
3270 	mono_copy_value (field->type, dest, value, FALSE);
3271 }
3272 
3273 /**
3274  * mono_vtable_get_static_field_data:
3275  *
3276  * Internal use function: return a pointer to the memory holding the static fields
3277  * for a class or NULL if there are no static fields.
3278  * This is exported only for use by the debugger.
3279  */
3280 void *
mono_vtable_get_static_field_data(MonoVTable * vt)3281 mono_vtable_get_static_field_data (MonoVTable *vt)
3282 {
3283 	MONO_REQ_GC_NEUTRAL_MODE
3284 
3285 	if (!vt->has_static_fields)
3286 		return NULL;
3287 	return vt->vtable [vt->klass->vtable_size];
3288 }
3289 
3290 static guint8*
mono_field_get_addr(MonoObject * obj,MonoVTable * vt,MonoClassField * field)3291 mono_field_get_addr (MonoObject *obj, MonoVTable *vt, MonoClassField *field)
3292 {
3293 	MONO_REQ_GC_UNSAFE_MODE;
3294 
3295 	guint8 *src;
3296 
3297 	if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
3298 		if (field->offset == -1) {
3299 			/* Special static */
3300 			gpointer addr;
3301 
3302 			mono_domain_lock (vt->domain);
3303 			addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3304 			mono_domain_unlock (vt->domain);
3305 			src = (guint8 *)mono_get_special_static_data (GPOINTER_TO_UINT (addr));
3306 		} else {
3307 			src = (guint8*)mono_vtable_get_static_field_data (vt) + field->offset;
3308 		}
3309 	} else {
3310 		src = (guint8*)obj + field->offset;
3311 	}
3312 
3313 	return src;
3314 }
3315 
3316 /**
3317  * mono_field_get_value:
3318  * \param obj Object instance
3319  * \param field \c MonoClassField describing the field to fetch information from
3320  * \param value pointer to the location where the value will be stored
3321  * Use this routine to get the value of the field \p field in the object
3322  * passed.
3323  *
3324  * The pointer provided by value must be of the field type, for reference
3325  * types this is a \c MonoObject*, for value types its the actual pointer to
3326  * the value type.
3327  *
3328  * For example:
3329  *
3330  * <pre>
3331  * int i;
3332  *
3333  * mono_field_get_value (obj, int_field, &i);
3334  * </pre>
3335  */
3336 void
mono_field_get_value(MonoObject * obj,MonoClassField * field,void * value)3337 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
3338 {
3339 	MONO_REQ_GC_UNSAFE_MODE;
3340 
3341 	void *src;
3342 
3343 	g_assert (obj);
3344 
3345 	g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
3346 
3347 	src = (char*)obj + field->offset;
3348 	mono_copy_value (field->type, value, src, TRUE);
3349 }
3350 
3351 /**
3352  * mono_field_get_value_object:
3353  * \param domain domain where the object will be created (if boxing)
3354  * \param field \c MonoClassField describing the field to fetch information from
3355  * \param obj The object instance for the field.
3356  * \returns a new \c MonoObject with the value from the given field.  If the
3357  * field represents a value type, the value is boxed.
3358  */
3359 MonoObject *
mono_field_get_value_object(MonoDomain * domain,MonoClassField * field,MonoObject * obj)3360 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
3361 {
3362 	MonoError error;
3363 	MonoObject* result = mono_field_get_value_object_checked (domain, field, obj, &error);
3364 	mono_error_assert_ok (&error);
3365 	return result;
3366 }
3367 
3368 /**
3369  * mono_field_get_value_object_checked:
3370  * \param domain domain where the object will be created (if boxing)
3371  * \param field \c MonoClassField describing the field to fetch information from
3372  * \param obj The object instance for the field.
3373  * \param error Set on error.
3374  * \returns a new \c MonoObject with the value from the given field.  If the
3375  * field represents a value type, the value is boxed.  On error returns NULL and sets \p error.
3376  */
3377 MonoObject *
mono_field_get_value_object_checked(MonoDomain * domain,MonoClassField * field,MonoObject * obj,MonoError * error)3378 mono_field_get_value_object_checked (MonoDomain *domain, MonoClassField *field, MonoObject *obj, MonoError *error)
3379 {
3380 	MONO_REQ_GC_UNSAFE_MODE;
3381 
3382 	error_init (error);
3383 
3384 	MonoObject *o;
3385 	MonoClass *klass;
3386 	MonoVTable *vtable = NULL;
3387 	gchar *v;
3388 	gboolean is_static = FALSE;
3389 	gboolean is_ref = FALSE;
3390 	gboolean is_literal = FALSE;
3391 	gboolean is_ptr = FALSE;
3392 	MonoType *type = mono_field_get_type_checked (field, error);
3393 
3394 	return_val_if_nok (error, NULL);
3395 
3396 	switch (type->type) {
3397 	case MONO_TYPE_STRING:
3398 	case MONO_TYPE_OBJECT:
3399 	case MONO_TYPE_CLASS:
3400 	case MONO_TYPE_ARRAY:
3401 	case MONO_TYPE_SZARRAY:
3402 		is_ref = TRUE;
3403 		break;
3404 	case MONO_TYPE_U1:
3405 	case MONO_TYPE_I1:
3406 	case MONO_TYPE_BOOLEAN:
3407 	case MONO_TYPE_U2:
3408 	case MONO_TYPE_I2:
3409 	case MONO_TYPE_CHAR:
3410 	case MONO_TYPE_U:
3411 	case MONO_TYPE_I:
3412 	case MONO_TYPE_U4:
3413 	case MONO_TYPE_I4:
3414 	case MONO_TYPE_R4:
3415 	case MONO_TYPE_U8:
3416 	case MONO_TYPE_I8:
3417 	case MONO_TYPE_R8:
3418 	case MONO_TYPE_VALUETYPE:
3419 		is_ref = type->byref;
3420 		break;
3421 	case MONO_TYPE_GENERICINST:
3422 		is_ref = !mono_type_generic_inst_is_valuetype (type);
3423 		break;
3424 	case MONO_TYPE_PTR:
3425 		is_ptr = TRUE;
3426 		break;
3427 	default:
3428 		g_error ("type 0x%x not handled in "
3429 			 "mono_field_get_value_object", type->type);
3430 		return NULL;
3431 	}
3432 
3433 	if (type->attrs & FIELD_ATTRIBUTE_LITERAL)
3434 		is_literal = TRUE;
3435 
3436 	if (type->attrs & FIELD_ATTRIBUTE_STATIC) {
3437 		is_static = TRUE;
3438 
3439 		if (!is_literal) {
3440 			vtable = mono_class_vtable_full (domain, field->parent, error);
3441 			return_val_if_nok (error, NULL);
3442 
3443 			if (!vtable->initialized) {
3444 				mono_runtime_class_init_full (vtable, error);
3445 				return_val_if_nok (error, NULL);
3446 			}
3447 		}
3448 	} else {
3449 		g_assert (obj);
3450 	}
3451 
3452 	if (is_ref) {
3453 		if (is_literal) {
3454 			get_default_field_value (domain, field, &o, error);
3455 			return_val_if_nok (error, NULL);
3456 		} else if (is_static) {
3457 			mono_field_static_get_value_checked (vtable, field, &o, error);
3458 			return_val_if_nok (error, NULL);
3459 		} else {
3460 			mono_field_get_value (obj, field, &o);
3461 		}
3462 		return o;
3463 	}
3464 
3465 	if (is_ptr) {
3466 		static MonoMethod *m;
3467 		gpointer args [2];
3468 		gpointer *ptr;
3469 		gpointer v;
3470 
3471 		if (!m) {
3472 			MonoClass *ptr_klass = mono_class_get_pointer_class ();
3473 			m = mono_class_get_method_from_name_flags (ptr_klass, "Box", 2, METHOD_ATTRIBUTE_STATIC);
3474 			g_assert (m);
3475 		}
3476 
3477 		v = &ptr;
3478 		if (is_literal) {
3479 			get_default_field_value (domain, field, v, error);
3480 			return_val_if_nok (error, NULL);
3481 		} else if (is_static) {
3482 			mono_field_static_get_value_checked (vtable, field, v, error);
3483 			return_val_if_nok (error, NULL);
3484 		} else {
3485 			mono_field_get_value (obj, field, v);
3486 		}
3487 
3488 		/* MONO_TYPE_PTR is passed by value to runtime_invoke () */
3489 		args [0] = ptr ? *ptr : NULL;
3490 		args [1] = mono_type_get_object_checked (mono_domain_get (), type, error);
3491 		return_val_if_nok (error, NULL);
3492 
3493 		o = mono_runtime_invoke_checked (m, NULL, args, error);
3494 		return_val_if_nok (error, NULL);
3495 
3496 		return o;
3497 	}
3498 
3499 	/* boxed value type */
3500 	klass = mono_class_from_mono_type (type);
3501 
3502 	if (mono_class_is_nullable (klass))
3503 		return mono_nullable_box (mono_field_get_addr (obj, vtable, field), klass, error);
3504 
3505 	o = mono_object_new_checked (domain, klass, error);
3506 	return_val_if_nok (error, NULL);
3507 	v = ((gchar *) o) + sizeof (MonoObject);
3508 
3509 	if (is_literal) {
3510 		get_default_field_value (domain, field, v, error);
3511 		return_val_if_nok (error, NULL);
3512 	} else if (is_static) {
3513 		mono_field_static_get_value_checked (vtable, field, v, error);
3514 		return_val_if_nok (error, NULL);
3515 	} else {
3516 		mono_field_get_value (obj, field, v);
3517 	}
3518 
3519 	return o;
3520 }
3521 
3522 int
mono_get_constant_value_from_blob(MonoDomain * domain,MonoTypeEnum type,const char * blob,void * value,MonoError * error)3523 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value, MonoError *error)
3524 {
3525 	MONO_REQ_GC_UNSAFE_MODE;
3526 
3527 	error_init (error);
3528 	int retval = 0;
3529 	const char *p = blob;
3530 	mono_metadata_decode_blob_size (p, &p);
3531 
3532 	switch (type) {
3533 	case MONO_TYPE_BOOLEAN:
3534 	case MONO_TYPE_U1:
3535 	case MONO_TYPE_I1:
3536 		*(guint8 *) value = *p;
3537 		break;
3538 	case MONO_TYPE_CHAR:
3539 	case MONO_TYPE_U2:
3540 	case MONO_TYPE_I2:
3541 		*(guint16*) value = read16 (p);
3542 		break;
3543 	case MONO_TYPE_U4:
3544 	case MONO_TYPE_I4:
3545 		*(guint32*) value = read32 (p);
3546 		break;
3547 	case MONO_TYPE_U8:
3548 	case MONO_TYPE_I8:
3549 		*(guint64*) value = read64 (p);
3550 		break;
3551 	case MONO_TYPE_R4:
3552 		readr4 (p, (float*) value);
3553 		break;
3554 	case MONO_TYPE_R8:
3555 		readr8 (p, (double*) value);
3556 		break;
3557 	case MONO_TYPE_STRING:
3558 		*(gpointer*) value = mono_ldstr_metadata_sig (domain, blob, error);
3559 		break;
3560 	case MONO_TYPE_CLASS:
3561 		*(gpointer*) value = NULL;
3562 		break;
3563 	default:
3564 		retval = -1;
3565 		g_warning ("type 0x%02x should not be in constant table", type);
3566 	}
3567 	return retval;
3568 }
3569 
3570 static void
get_default_field_value(MonoDomain * domain,MonoClassField * field,void * value,MonoError * error)3571 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value, MonoError *error)
3572 {
3573 	MONO_REQ_GC_NEUTRAL_MODE;
3574 
3575 	MonoTypeEnum def_type;
3576 	const char* data;
3577 
3578 	error_init (error);
3579 
3580 	data = mono_class_get_field_default_value (field, &def_type);
3581 	mono_get_constant_value_from_blob (domain, def_type, data, value, error);
3582 }
3583 
3584 void
mono_field_static_get_value_for_thread(MonoInternalThread * thread,MonoVTable * vt,MonoClassField * field,void * value,MonoError * error)3585 mono_field_static_get_value_for_thread (MonoInternalThread *thread, MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3586 {
3587 	MONO_REQ_GC_UNSAFE_MODE;
3588 
3589 	void *src;
3590 
3591 	error_init (error);
3592 
3593 	g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
3594 
3595 	if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
3596 		get_default_field_value (vt->domain, field, value, error);
3597 		return;
3598 	}
3599 
3600 	if (field->offset == -1) {
3601 		/* Special static */
3602 		gpointer addr = g_hash_table_lookup (vt->domain->special_static_fields, field);
3603 		src = mono_get_special_static_data_for_thread (thread, GPOINTER_TO_UINT (addr));
3604 	} else {
3605 		src = (char*)mono_vtable_get_static_field_data (vt) + field->offset;
3606 	}
3607 	mono_copy_value (field->type, value, src, TRUE);
3608 }
3609 
3610 /**
3611  * mono_field_static_get_value:
3612  * \param vt vtable to the object
3613  * \param field \c MonoClassField describing the field to fetch information from
3614  * \param value where the value is returned
3615  * Use this routine to get the value of the static field \p field value.
3616  *
3617  * The pointer provided by value must be of the field type, for reference
3618  * types this is a \c MonoObject*, for value types its the actual pointer to
3619  * the value type.
3620  *
3621  * For example:
3622  *
3623  * <pre>
3624  *     int i;
3625  *
3626  *     mono_field_static_get_value (vt, int_field, &i);
3627  * </pre>
3628  */
3629 void
mono_field_static_get_value(MonoVTable * vt,MonoClassField * field,void * value)3630 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
3631 {
3632 	MONO_REQ_GC_NEUTRAL_MODE;
3633 
3634 	MonoError error;
3635 	mono_field_static_get_value_checked (vt, field, value, &error);
3636 	mono_error_cleanup (&error);
3637 }
3638 
3639 /**
3640  * mono_field_static_get_value_checked:
3641  * \param vt vtable to the object
3642  * \param field \c MonoClassField describing the field to fetch information from
3643  * \param value where the value is returned
3644  * \param error set on error
3645  * Use this routine to get the value of the static field \p field value.
3646  *
3647  * The pointer provided by value must be of the field type, for reference
3648  * types this is a \c MonoObject*, for value types its the actual pointer to
3649  * the value type.
3650  *
3651  * For example:
3652  *     int i;
3653  *     mono_field_static_get_value_checked (vt, int_field, &i, error);
3654  *     if (!is_ok (error)) { ... }
3655  *
3656  * On failure sets \p error.
3657  */
3658 void
mono_field_static_get_value_checked(MonoVTable * vt,MonoClassField * field,void * value,MonoError * error)3659 mono_field_static_get_value_checked (MonoVTable *vt, MonoClassField *field, void *value, MonoError *error)
3660 {
3661 	MONO_REQ_GC_NEUTRAL_MODE;
3662 
3663 	mono_field_static_get_value_for_thread (mono_thread_internal_current (), vt, field, value, error);
3664 }
3665 
3666 /**
3667  * mono_property_set_value:
3668  * \param prop MonoProperty to set
3669  * \param obj instance object on which to act
3670  * \param params parameters to pass to the propery
3671  * \param exc optional exception
3672  * Invokes the property's set method with the given arguments on the
3673  * object instance obj (or NULL for static properties).
3674  *
3675  * You can pass NULL as the exc argument if you don't want to
3676  * catch exceptions, otherwise, \c *exc will be set to the exception
3677  * thrown, if any.  if an exception is thrown, you can't use the
3678  * \c MonoObject* result from the function.
3679  */
3680 void
mono_property_set_value(MonoProperty * prop,void * obj,void ** params,MonoObject ** exc)3681 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3682 {
3683 	MONO_REQ_GC_UNSAFE_MODE;
3684 
3685 	MonoError error;
3686 	do_runtime_invoke (prop->set, obj, params, exc, &error);
3687 	if (exc && *exc == NULL && !mono_error_ok (&error)) {
3688 		*exc = (MonoObject*) mono_error_convert_to_exception (&error);
3689 	} else {
3690 		mono_error_cleanup (&error);
3691 	}
3692 }
3693 
3694 /**
3695  * mono_property_set_value_checked:
3696  * \param prop \c MonoProperty to set
3697  * \param obj instance object on which to act
3698  * \param params parameters to pass to the propery
3699  * \param error set on error
3700  * Invokes the property's set method with the given arguments on the
3701  * object instance \p obj (or NULL for static properties).
3702  * \returns TRUE on success.  On failure returns FALSE and sets \p error.
3703  * If an exception is thrown, it will be caught and returned via \p error.
3704  */
3705 gboolean
mono_property_set_value_checked(MonoProperty * prop,void * obj,void ** params,MonoError * error)3706 mono_property_set_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3707 {
3708 	MONO_REQ_GC_UNSAFE_MODE;
3709 
3710 	MonoObject *exc;
3711 
3712 	error_init (error);
3713 	do_runtime_invoke (prop->set, obj, params, &exc, error);
3714 	if (exc != NULL && is_ok (error))
3715 		mono_error_set_exception_instance (error, (MonoException*)exc);
3716 	return is_ok (error);
3717 }
3718 
3719 /**
3720  * mono_property_get_value:
3721  * \param prop \c MonoProperty to fetch
3722  * \param obj instance object on which to act
3723  * \param params parameters to pass to the propery
3724  * \param exc optional exception
3725  * Invokes the property's \c get method with the given arguments on the
3726  * object instance \p obj (or NULL for static properties).
3727  *
3728  * You can pass NULL as the \p exc argument if you don't want to
3729  * catch exceptions, otherwise, \c *exc will be set to the exception
3730  * thrown, if any.  if an exception is thrown, you can't use the
3731  * \c MonoObject* result from the function.
3732  *
3733  * \returns the value from invoking the \c get method on the property.
3734  */
3735 MonoObject*
mono_property_get_value(MonoProperty * prop,void * obj,void ** params,MonoObject ** exc)3736 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
3737 {
3738 	MONO_REQ_GC_UNSAFE_MODE;
3739 
3740 	MonoError error;
3741 	MonoObject *val = do_runtime_invoke (prop->get, obj, params, exc, &error);
3742 	if (exc && *exc == NULL && !mono_error_ok (&error)) {
3743 		*exc = (MonoObject*) mono_error_convert_to_exception (&error);
3744 	} else {
3745 		mono_error_cleanup (&error); /* FIXME don't raise here */
3746 	}
3747 
3748 	return val;
3749 }
3750 
3751 /**
3752  * mono_property_get_value_checked:
3753  * \param prop \c MonoProperty to fetch
3754  * \param obj instance object on which to act
3755  * \param params parameters to pass to the propery
3756  * \param error set on error
3757  * Invokes the property's \c get method with the given arguments on the
3758  * object instance obj (or NULL for static properties).
3759  *
3760  * If an exception is thrown, you can't use the
3761  * \c MonoObject* result from the function.  The exception will be propagated via \p error.
3762  *
3763  * \returns the value from invoking the get method on the property. On
3764  * failure returns NULL and sets \p error.
3765  */
3766 MonoObject*
mono_property_get_value_checked(MonoProperty * prop,void * obj,void ** params,MonoError * error)3767 mono_property_get_value_checked (MonoProperty *prop, void *obj, void **params, MonoError *error)
3768 {
3769 	MONO_REQ_GC_UNSAFE_MODE;
3770 
3771 	MonoObject *exc;
3772 	MonoObject *val = do_runtime_invoke (prop->get, obj, params, &exc, error);
3773 	if (exc != NULL && !is_ok (error))
3774 		mono_error_set_exception_instance (error, (MonoException*) exc);
3775 	if (!is_ok (error))
3776 		val = NULL;
3777 	return val;
3778 }
3779 
3780 
3781 /*
3782  * mono_nullable_init:
3783  * @buf: The nullable structure to initialize.
3784  * @value: the value to initialize from
3785  * @klass: the type for the object
3786  *
3787  * Initialize the nullable structure pointed to by @buf from @value which
3788  * should be a boxed value type.   The size of @buf should be able to hold
3789  * as much data as the @klass->instance_size (which is the number of bytes
3790  * that will be copies).
3791  *
3792  * Since Nullables have variable structure, we can not define a C
3793  * structure for them.
3794  */
3795 void
mono_nullable_init(guint8 * buf,MonoObject * value,MonoClass * klass)3796 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
3797 {
3798 	MONO_REQ_GC_UNSAFE_MODE;
3799 
3800 	MonoClass *param_class = klass->cast_class;
3801 
3802 	mono_class_setup_fields (klass);
3803 	g_assert (klass->fields_inited);
3804 
3805 	g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3806 	g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3807 
3808 	*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
3809 	if (value) {
3810 		if (param_class->has_references)
3811 			mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), 1, param_class);
3812 		else
3813 			mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
3814 	} else {
3815 		mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3816 	}
3817 }
3818 
3819 /*
3820  * mono_nullable_init_from_handle:
3821  * @buf: The nullable structure to initialize.
3822  * @value: the value to initialize from
3823  * @klass: the type for the object
3824  *
3825  * Initialize the nullable structure pointed to by @buf from @value which
3826  * should be a boxed value type.   The size of @buf should be able to hold
3827  * as much data as the @klass->instance_size (which is the number of bytes
3828  * that will be copies).
3829  *
3830  * Since Nullables have variable structure, we can not define a C
3831  * structure for them.
3832  */
3833 void
mono_nullable_init_from_handle(guint8 * buf,MonoObjectHandle value,MonoClass * klass)3834 mono_nullable_init_from_handle (guint8 *buf, MonoObjectHandle value, MonoClass *klass)
3835 {
3836 	MONO_REQ_GC_UNSAFE_MODE;
3837 
3838 	MonoClass *param_class = klass->cast_class;
3839 
3840 	mono_class_setup_fields (klass);
3841 	g_assert (klass->fields_inited);
3842 
3843 	g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3844 	g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3845 
3846 	*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = MONO_HANDLE_IS_NULL  (value) ? 0 : 1;
3847 	if (!MONO_HANDLE_IS_NULL (value)) {
3848 		uint32_t value_gchandle = 0;
3849 		gpointer src = mono_object_handle_pin_unbox (value, &value_gchandle);
3850 		if (param_class->has_references)
3851 			mono_gc_wbarrier_value_copy (buf + klass->fields [0].offset - sizeof (MonoObject), src, 1, param_class);
3852 		else
3853 			mono_gc_memmove_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), src, mono_class_value_size (param_class, NULL));
3854 		mono_gchandle_free (value_gchandle);
3855 	} else {
3856 		mono_gc_bzero_atomic (buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3857 	}
3858 }
3859 
3860 
3861 
3862 /**
3863  * mono_nullable_box:
3864  * \param buf The buffer representing the data to be boxed
3865  * \param klass the type to box it as.
3866  * \param error set on error
3867  *
3868  * Creates a boxed vtype or NULL from the \c Nullable structure pointed to by
3869  * \p buf.  On failure returns NULL and sets \p error.
3870  */
3871 MonoObject*
mono_nullable_box(guint8 * buf,MonoClass * klass,MonoError * error)3872 mono_nullable_box (guint8 *buf, MonoClass *klass, MonoError *error)
3873 {
3874 	MONO_REQ_GC_UNSAFE_MODE;
3875 
3876 	error_init (error);
3877 	MonoClass *param_class = klass->cast_class;
3878 
3879 	mono_class_setup_fields (klass);
3880 	g_assert (klass->fields_inited);
3881 
3882 	g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
3883 	g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
3884 
3885 	if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
3886 		MonoObject *o = mono_object_new_checked (mono_domain_get (), param_class, error);
3887 		return_val_if_nok (error, NULL);
3888 		if (param_class->has_references)
3889 			mono_gc_wbarrier_value_copy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), 1, param_class);
3890 		else
3891 			mono_gc_memmove_atomic (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
3892 		return o;
3893 	}
3894 	else
3895 		return NULL;
3896 }
3897 
3898 /**
3899  * mono_get_delegate_invoke:
3900  * \param klass The delegate class
3901  * \returns the \c MonoMethod for the \c Invoke method in the delegate class or NULL if \p klass is a broken delegate type
3902  */
3903 MonoMethod *
mono_get_delegate_invoke(MonoClass * klass)3904 mono_get_delegate_invoke (MonoClass *klass)
3905 {
3906 	MONO_REQ_GC_NEUTRAL_MODE;
3907 
3908 	MonoMethod *im;
3909 
3910 	/* This is called at runtime, so avoid the slower search in metadata */
3911 	mono_class_setup_methods (klass);
3912 	if (mono_class_has_failure (klass))
3913 		return NULL;
3914 	im = mono_class_get_method_from_name (klass, "Invoke", -1);
3915 	return im;
3916 }
3917 
3918 /**
3919  * mono_get_delegate_begin_invoke:
3920  * \param klass The delegate class
3921  * \returns the \c MonoMethod for the \c BeginInvoke method in the delegate class or NULL if \p klass is a broken delegate type
3922  */
3923 MonoMethod *
mono_get_delegate_begin_invoke(MonoClass * klass)3924 mono_get_delegate_begin_invoke (MonoClass *klass)
3925 {
3926 	MONO_REQ_GC_NEUTRAL_MODE;
3927 
3928 	MonoMethod *im;
3929 
3930 	/* This is called at runtime, so avoid the slower search in metadata */
3931 	mono_class_setup_methods (klass);
3932 	if (mono_class_has_failure (klass))
3933 		return NULL;
3934 	im = mono_class_get_method_from_name (klass, "BeginInvoke", -1);
3935 	return im;
3936 }
3937 
3938 /**
3939  * mono_get_delegate_end_invoke:
3940  * \param klass The delegate class
3941  * \returns the \c MonoMethod for the \c EndInvoke method in the delegate class or NULL if \p klass is a broken delegate type
3942  */
3943 MonoMethod *
mono_get_delegate_end_invoke(MonoClass * klass)3944 mono_get_delegate_end_invoke (MonoClass *klass)
3945 {
3946 	MONO_REQ_GC_NEUTRAL_MODE;
3947 
3948 	MonoMethod *im;
3949 
3950 	/* This is called at runtime, so avoid the slower search in metadata */
3951 	mono_class_setup_methods (klass);
3952 	if (mono_class_has_failure (klass))
3953 		return NULL;
3954 	im = mono_class_get_method_from_name (klass, "EndInvoke", -1);
3955 	return im;
3956 }
3957 
3958 /**
3959  * mono_runtime_delegate_invoke:
3960  * \param delegate pointer to a delegate object.
3961  * \param params parameters for the delegate.
3962  * \param exc Pointer to the exception result.
3963  *
3964  * Invokes the delegate method \p delegate with the parameters provided.
3965  *
3966  * You can pass NULL as the \p exc argument if you don't want to
3967  * catch exceptions, otherwise, \c *exc will be set to the exception
3968  * thrown, if any.  if an exception is thrown, you can't use the
3969  * \c MonoObject* result from the function.
3970  */
3971 MonoObject*
mono_runtime_delegate_invoke(MonoObject * delegate,void ** params,MonoObject ** exc)3972 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
3973 {
3974 	MONO_REQ_GC_UNSAFE_MODE;
3975 
3976 	MonoError error;
3977 	if (exc) {
3978 		MonoObject *result = mono_runtime_delegate_try_invoke (delegate, params, exc, &error);
3979 		if (*exc) {
3980 			mono_error_cleanup (&error);
3981 			return NULL;
3982 		} else {
3983 			if (!is_ok (&error))
3984 				*exc = (MonoObject*)mono_error_convert_to_exception (&error);
3985 			return result;
3986 		}
3987 	} else {
3988 		MonoObject *result = mono_runtime_delegate_invoke_checked (delegate, params, &error);
3989 		mono_error_raise_exception_deprecated (&error); /* OK to throw, external only without a good alternative */
3990 		return result;
3991 	}
3992 }
3993 
3994 /**
3995  * mono_runtime_delegate_try_invoke:
3996  * \param delegate pointer to a delegate object.
3997  * \param params parameters for the delegate.
3998  * \param exc Pointer to the exception result.
3999  * \param error set on error
4000  * Invokes the delegate method \p delegate with the parameters provided.
4001  *
4002  * You can pass NULL as the \p exc argument if you don't want to
4003  * catch exceptions, otherwise, \c *exc will be set to the exception
4004  * thrown, if any.  On failure to execute, \p error will be set.
4005  * if an exception is thrown, you can't use the
4006  * \c MonoObject* result from the function.
4007  */
4008 MonoObject*
mono_runtime_delegate_try_invoke(MonoObject * delegate,void ** params,MonoObject ** exc,MonoError * error)4009 mono_runtime_delegate_try_invoke (MonoObject *delegate, void **params, MonoObject **exc, MonoError *error)
4010 {
4011 	MONO_REQ_GC_UNSAFE_MODE;
4012 
4013 	error_init (error);
4014 	MonoMethod *im;
4015 	MonoClass *klass = delegate->vtable->klass;
4016 	MonoObject *o;
4017 
4018 	im = mono_get_delegate_invoke (klass);
4019 	if (!im)
4020 		g_error ("Could not lookup delegate invoke method for delegate %s", mono_type_get_full_name (klass));
4021 
4022 	if (exc) {
4023 		o = mono_runtime_try_invoke (im, delegate, params, exc, error);
4024 	} else {
4025 		o = mono_runtime_invoke_checked (im, delegate, params, error);
4026 	}
4027 
4028 	return o;
4029 }
4030 
4031 /**
4032  * mono_runtime_delegate_invoke_checked:
4033  * \param delegate pointer to a delegate object.
4034  * \param params parameters for the delegate.
4035  * \param error set on error
4036  * Invokes the delegate method \p delegate with the parameters provided.
4037  * On failure \p error will be set and you can't use the \c MonoObject*
4038  * result from the function.
4039  */
4040 MonoObject*
mono_runtime_delegate_invoke_checked(MonoObject * delegate,void ** params,MonoError * error)4041 mono_runtime_delegate_invoke_checked (MonoObject *delegate, void **params, MonoError *error)
4042 {
4043 	error_init (error);
4044 	return mono_runtime_delegate_try_invoke (delegate, params, NULL, error);
4045 }
4046 
4047 static char **main_args = NULL;
4048 static int num_main_args = 0;
4049 
4050 /**
4051  * mono_runtime_get_main_args:
4052  * \returns A \c MonoArray with the arguments passed to the main program
4053  */
4054 MonoArray*
mono_runtime_get_main_args(void)4055 mono_runtime_get_main_args (void)
4056 {
4057 	HANDLE_FUNCTION_ENTER ();
4058 	MONO_REQ_GC_UNSAFE_MODE;
4059 	MonoError error;
4060 	MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
4061 	error_init (&error);
4062 	MonoArrayHandle arg_array = mono_runtime_get_main_args_handle (&error);
4063 	goto_if_nok (&error, leave);
4064 	MONO_HANDLE_ASSIGN (result, arg_array);
4065 leave:
4066 	/* FIXME: better external API that doesn't swallow the error */
4067 	mono_error_cleanup (&error);
4068 	HANDLE_FUNCTION_RETURN_OBJ (result);
4069 }
4070 
4071 static gboolean
handle_main_arg_array_set(MonoDomain * domain,int idx,MonoArrayHandle dest,MonoError * error)4072 handle_main_arg_array_set (MonoDomain *domain, int idx, MonoArrayHandle dest, MonoError *error)
4073 {
4074 	HANDLE_FUNCTION_ENTER ();
4075 	error_init (error);
4076 	MonoStringHandle value = mono_string_new_handle (domain, main_args [idx], error);
4077 	goto_if_nok (error, leave);
4078 	MONO_HANDLE_ARRAY_SETREF (dest, idx, value);
4079 leave:
4080 	HANDLE_FUNCTION_RETURN_VAL (is_ok (error));
4081 }
4082 
4083 /**
4084  * mono_runtime_get_main_args_handle:
4085  * \param error set on error
4086  * \returns a \c MonoArray with the arguments passed to the main
4087  * program. On failure returns NULL and sets \p error.
4088  */
4089 MonoArrayHandle
mono_runtime_get_main_args_handle(MonoError * error)4090 mono_runtime_get_main_args_handle (MonoError *error)
4091 {
4092 	HANDLE_FUNCTION_ENTER ();
4093 	MonoArrayHandle array;
4094 	int i;
4095 	MonoDomain *domain = mono_domain_get ();
4096 	error_init (error);
4097 
4098 	array = mono_array_new_handle (domain, mono_defaults.string_class, num_main_args, error);
4099 	if (!is_ok (error)) {
4100 		array = MONO_HANDLE_CAST (MonoArray, NULL_HANDLE);
4101 		goto leave;
4102 	}
4103 	for (i = 0; i < num_main_args; ++i) {
4104 		if (!handle_main_arg_array_set (domain, i, array, error))
4105 			goto leave;
4106 	}
4107 leave:
4108 	HANDLE_FUNCTION_RETURN_REF (MonoArray, array);
4109 }
4110 
4111 static void
free_main_args(void)4112 free_main_args (void)
4113 {
4114 	MONO_REQ_GC_NEUTRAL_MODE;
4115 
4116 	int i;
4117 
4118 	for (i = 0; i < num_main_args; ++i)
4119 		g_free (main_args [i]);
4120 	g_free (main_args);
4121 	num_main_args = 0;
4122 	main_args = NULL;
4123 }
4124 
4125 /**
4126  * mono_runtime_set_main_args:
4127  * \param argc number of arguments from the command line
4128  * \param argv array of strings from the command line
4129  * Set the command line arguments from an embedding application that doesn't otherwise call
4130  * \c mono_runtime_run_main.
4131  */
4132 int
mono_runtime_set_main_args(int argc,char * argv[])4133 mono_runtime_set_main_args (int argc, char* argv[])
4134 {
4135 	MONO_REQ_GC_NEUTRAL_MODE;
4136 
4137 	int i;
4138 
4139 	free_main_args ();
4140 	main_args = g_new0 (char*, argc);
4141 	num_main_args = argc;
4142 
4143 	for (i = 0; i < argc; ++i) {
4144 		gchar *utf8_arg;
4145 
4146 		utf8_arg = mono_utf8_from_external (argv[i]);
4147 		if (utf8_arg == NULL) {
4148 			g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv [i]);
4149 			g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4150 			exit (-1);
4151 		}
4152 
4153 		main_args [i] = utf8_arg;
4154 	}
4155 
4156 	return 0;
4157 }
4158 
4159 /*
4160  * Prepare an array of arguments in order to execute a standard Main()
4161  * method (argc/argv contains the executable name). This method also
4162  * sets the command line argument value needed by System.Environment.
4163  *
4164  */
4165 static MonoArray*
prepare_run_main(MonoMethod * method,int argc,char * argv[])4166 prepare_run_main (MonoMethod *method, int argc, char *argv[])
4167 {
4168 	MONO_REQ_GC_UNSAFE_MODE;
4169 
4170 	MonoError error;
4171 	int i;
4172 	MonoArray *args = NULL;
4173 	MonoDomain *domain = mono_domain_get ();
4174 	gchar *utf8_fullpath;
4175 	MonoMethodSignature *sig;
4176 
4177 	g_assert (method != NULL);
4178 
4179 	mono_thread_set_main (mono_thread_current ());
4180 
4181 	main_args = g_new0 (char*, argc);
4182 	num_main_args = argc;
4183 
4184 	if (!g_path_is_absolute (argv [0])) {
4185 		gchar *basename = g_path_get_basename (argv [0]);
4186 		gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
4187 						    basename,
4188 						    NULL);
4189 
4190 		utf8_fullpath = mono_utf8_from_external (fullpath);
4191 		if(utf8_fullpath == NULL) {
4192 			/* Printing the arg text will cause glib to
4193 			 * whinge about "Invalid UTF-8", but at least
4194 			 * its relevant, and shows the problem text
4195 			 * string.
4196 			 */
4197 			g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
4198 			g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4199 			exit (-1);
4200 		}
4201 
4202 		g_free (fullpath);
4203 		g_free (basename);
4204 	} else {
4205 		utf8_fullpath = mono_utf8_from_external (argv[0]);
4206 		if(utf8_fullpath == NULL) {
4207 			g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
4208 			g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4209 			exit (-1);
4210 		}
4211 	}
4212 
4213 	main_args [0] = utf8_fullpath;
4214 
4215 	for (i = 1; i < argc; ++i) {
4216 		gchar *utf8_arg;
4217 
4218 		utf8_arg=mono_utf8_from_external (argv[i]);
4219 		if(utf8_arg==NULL) {
4220 			/* Ditto the comment about Invalid UTF-8 here */
4221 			g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
4222 			g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
4223 			exit (-1);
4224 		}
4225 
4226 		main_args [i] = utf8_arg;
4227 	}
4228 	argc--;
4229 	argv++;
4230 
4231 	sig = mono_method_signature (method);
4232 	if (!sig) {
4233 		g_print ("Unable to load Main method.\n");
4234 		exit (-1);
4235 	}
4236 
4237 	if (sig->param_count) {
4238 		args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, argc, &error);
4239 		mono_error_assert_ok (&error);
4240 		for (i = 0; i < argc; ++i) {
4241 			/* The encodings should all work, given that
4242 			 * we've checked all these args for the
4243 			 * main_args array.
4244 			 */
4245 			gchar *str = mono_utf8_from_external (argv [i]);
4246 			MonoString *arg = mono_string_new_checked (domain, str, &error);
4247 			mono_error_assert_ok (&error);
4248 			mono_array_setref (args, i, arg);
4249 			g_free (str);
4250 		}
4251 	} else {
4252 		args = (MonoArray*)mono_array_new_checked (domain, mono_defaults.string_class, 0, &error);
4253 		mono_error_assert_ok (&error);
4254 	}
4255 
4256 	mono_assembly_set_main (method->klass->image->assembly);
4257 
4258 	return args;
4259 }
4260 
4261 /**
4262  * mono_runtime_run_main:
4263  * \param method the method to start the application with (usually <code>Main</code>)
4264  * \param argc number of arguments from the command line
4265  * \param argv array of strings from the command line
4266  * \param exc excetption results
4267  * Execute a standard \c Main method (\p argc / \p argv contains the
4268  * executable name). This method also sets the command line argument value
4269  * needed by \c System.Environment.
4270  */
4271 int
mono_runtime_run_main(MonoMethod * method,int argc,char * argv[],MonoObject ** exc)4272 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
4273 		       MonoObject **exc)
4274 {
4275 	MONO_REQ_GC_UNSAFE_MODE;
4276 
4277 	MonoError error;
4278 	MonoArray *args = prepare_run_main (method, argc, argv);
4279 	int res;
4280 	if (exc) {
4281 		res = mono_runtime_try_exec_main (method, args, exc);
4282 	} else {
4283 		res = mono_runtime_exec_main_checked (method, args, &error);
4284 		mono_error_raise_exception_deprecated (&error); /* OK to throw, external only without a better alternative */
4285 	}
4286 	return res;
4287 }
4288 
4289 /**
4290  * mono_runtime_run_main_checked:
4291  * \param method the method to start the application with (usually \c Main)
4292  * \param argc number of arguments from the command line
4293  * \param argv array of strings from the command line
4294  * \param error set on error
4295  *
4296  * Execute a standard \c Main method (\p argc / \p argv contains the
4297  * executable name). This method also sets the command line argument value
4298  * needed by \c System.Environment.  On failure sets \p error.
4299  */
4300 int
mono_runtime_run_main_checked(MonoMethod * method,int argc,char * argv[],MonoError * error)4301 mono_runtime_run_main_checked (MonoMethod *method, int argc, char* argv[],
4302 			       MonoError *error)
4303 {
4304 	error_init (error);
4305 	MonoArray *args = prepare_run_main (method, argc, argv);
4306 	return mono_runtime_exec_main_checked (method, args, error);
4307 }
4308 
4309 /**
4310  * mono_runtime_try_run_main:
4311  * \param method the method to start the application with (usually \c Main)
4312  * \param argc number of arguments from the command line
4313  * \param argv array of strings from the command line
4314  * \param exc set if \c Main throws an exception
4315  * \param error set if \c Main can't be executed
4316  * Execute a standard \c Main method (\p argc / \p argv contains the executable
4317  * name). This method also sets the command line argument value needed
4318  * by \c System.Environment.  On failure sets \p error if Main can't be
4319  * executed or \p exc if it threw an exception.
4320  */
4321 int
mono_runtime_try_run_main(MonoMethod * method,int argc,char * argv[],MonoObject ** exc)4322 mono_runtime_try_run_main (MonoMethod *method, int argc, char* argv[],
4323 			   MonoObject **exc)
4324 {
4325 	g_assert (exc);
4326 	MonoArray *args = prepare_run_main (method, argc, argv);
4327 	return mono_runtime_try_exec_main (method, args, exc);
4328 }
4329 
4330 
4331 static MonoObject*
serialize_object(MonoObject * obj,gboolean * failure,MonoObject ** exc)4332 serialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4333 {
4334 	static MonoMethod *serialize_method;
4335 
4336 	MonoError error;
4337 	void *params [1];
4338 	MonoObject *array;
4339 
4340 	if (!serialize_method) {
4341 		MonoClass *klass = mono_class_get_remoting_services_class ();
4342 		serialize_method = mono_class_get_method_from_name (klass, "SerializeCallData", -1);
4343 	}
4344 
4345 	if (!serialize_method) {
4346 		*failure = TRUE;
4347 		return NULL;
4348 	}
4349 
4350 	g_assert (!mono_class_is_marshalbyref (mono_object_class (obj)));
4351 
4352 	params [0] = obj;
4353 	*exc = NULL;
4354 
4355 	array = mono_runtime_try_invoke (serialize_method, NULL, params, exc, &error);
4356 	if (*exc == NULL && !mono_error_ok (&error))
4357 		*exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert serialize_object to MonoError */
4358 	else
4359 		mono_error_cleanup (&error);
4360 
4361 	if (*exc)
4362 		*failure = TRUE;
4363 
4364 	return array;
4365 }
4366 
4367 static MonoObject*
deserialize_object(MonoObject * obj,gboolean * failure,MonoObject ** exc)4368 deserialize_object (MonoObject *obj, gboolean *failure, MonoObject **exc)
4369 {
4370 	MONO_REQ_GC_UNSAFE_MODE;
4371 
4372 	static MonoMethod *deserialize_method;
4373 
4374 	MonoError error;
4375 	void *params [1];
4376 	MonoObject *result;
4377 
4378 	if (!deserialize_method) {
4379 		MonoClass *klass = mono_class_get_remoting_services_class ();
4380 		deserialize_method = mono_class_get_method_from_name (klass, "DeserializeCallData", -1);
4381 	}
4382 	if (!deserialize_method) {
4383 		*failure = TRUE;
4384 		return NULL;
4385 	}
4386 
4387 	params [0] = obj;
4388 	*exc = NULL;
4389 
4390 	result = mono_runtime_try_invoke (deserialize_method, NULL, params, exc, &error);
4391 	if (*exc == NULL && !mono_error_ok (&error))
4392 		*exc = (MonoObject*) mono_error_convert_to_exception (&error); /* FIXME convert deserialize_object to MonoError */
4393 	else
4394 		mono_error_cleanup (&error);
4395 
4396 	if (*exc)
4397 		*failure = TRUE;
4398 
4399 	return result;
4400 }
4401 
4402 #ifndef DISABLE_REMOTING
4403 static MonoObject*
make_transparent_proxy(MonoObject * obj,MonoError * error)4404 make_transparent_proxy (MonoObject *obj, MonoError *error)
4405 {
4406 	MONO_REQ_GC_UNSAFE_MODE;
4407 
4408 	static MonoMethod *get_proxy_method;
4409 
4410 	MonoDomain *domain = mono_domain_get ();
4411 	MonoRealProxy *real_proxy;
4412 	MonoReflectionType *reflection_type;
4413 	MonoTransparentProxy *transparent_proxy;
4414 
4415 	error_init (error);
4416 
4417 	if (!get_proxy_method)
4418 		get_proxy_method = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "GetTransparentProxy", 0);
4419 
4420 	g_assert (mono_class_is_marshalbyref (obj->vtable->klass));
4421 
4422 	real_proxy = (MonoRealProxy*) mono_object_new_checked (domain, mono_defaults.real_proxy_class, error);
4423 	return_val_if_nok (error, NULL);
4424 	reflection_type = mono_type_get_object_checked (domain, &obj->vtable->klass->byval_arg, error);
4425 	return_val_if_nok (error, NULL);
4426 
4427 	MONO_OBJECT_SETREF (real_proxy, class_to_proxy, reflection_type);
4428 	MONO_OBJECT_SETREF (real_proxy, unwrapped_server, obj);
4429 
4430 	MonoObject *exc = NULL;
4431 
4432 	transparent_proxy = (MonoTransparentProxy*) mono_runtime_try_invoke (get_proxy_method, real_proxy, NULL, &exc, error);
4433 	if (exc != NULL && is_ok (error))
4434 		mono_error_set_exception_instance (error, (MonoException*)exc);
4435 
4436 	return (MonoObject*) transparent_proxy;
4437 }
4438 #endif /* DISABLE_REMOTING */
4439 
4440 /**
4441  * mono_object_xdomain_representation
4442  * \param obj an object
4443  * \param target_domain a domain
4444  * \param error set on error.
4445  * Creates a representation of obj in the domain \p target_domain.  This
4446  * is either a copy of \p obj arrived through via serialization and
4447  * deserialization or a proxy, depending on whether the object is
4448  * serializable or marshal by ref.  \p obj must not be in \p target_domain.
4449  * If the object cannot be represented in \p target_domain, NULL is
4450  * returned and \p error is set appropriately.
4451  */
4452 MonoObject*
mono_object_xdomain_representation(MonoObject * obj,MonoDomain * target_domain,MonoError * error)4453 mono_object_xdomain_representation (MonoObject *obj, MonoDomain *target_domain, MonoError *error)
4454 {
4455 	MONO_REQ_GC_UNSAFE_MODE;
4456 
4457 	error_init (error);
4458 	MonoObject *deserialized = NULL;
4459 
4460 #ifndef DISABLE_REMOTING
4461 	if (mono_class_is_marshalbyref (mono_object_class (obj))) {
4462 		deserialized = make_transparent_proxy (obj, error);
4463 	}
4464 	else
4465 #endif
4466 	{
4467 		gboolean failure = FALSE;
4468 		MonoDomain *domain = mono_domain_get ();
4469 		MonoObject *serialized;
4470 		MonoObject *exc = NULL;
4471 
4472 		mono_domain_set_internal_with_options (mono_object_domain (obj), FALSE);
4473 		serialized = serialize_object (obj, &failure, &exc);
4474 		mono_domain_set_internal_with_options (target_domain, FALSE);
4475 		if (!failure)
4476 			deserialized = deserialize_object (serialized, &failure, &exc);
4477 		if (domain != target_domain)
4478 			mono_domain_set_internal_with_options (domain, FALSE);
4479 		if (failure)
4480 			mono_error_set_exception_instance (error, (MonoException*)exc);
4481 	}
4482 
4483 	return deserialized;
4484 }
4485 
4486 /* Used in call_unhandled_exception_delegate */
4487 static MonoObject *
create_unhandled_exception_eventargs(MonoObject * exc,MonoError * error)4488 create_unhandled_exception_eventargs (MonoObject *exc, MonoError *error)
4489 {
4490 	MONO_REQ_GC_UNSAFE_MODE;
4491 
4492 	error_init (error);
4493 	MonoClass *klass;
4494 	gpointer args [2];
4495 	MonoMethod *method = NULL;
4496 	MonoBoolean is_terminating = TRUE;
4497 	MonoObject *obj;
4498 
4499 	klass = mono_class_get_unhandled_exception_event_args_class ();
4500 	mono_class_init (klass);
4501 
4502 	/* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
4503 	method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
4504 	g_assert (method);
4505 
4506 	args [0] = exc;
4507 	args [1] = &is_terminating;
4508 
4509 	obj = mono_object_new_checked (mono_domain_get (), klass, error);
4510 	return_val_if_nok (error, NULL);
4511 
4512 	mono_runtime_invoke_checked (method, obj, args, error);
4513 	return_val_if_nok (error, NULL);
4514 
4515 	return obj;
4516 }
4517 
4518 /* Used in mono_unhandled_exception */
4519 static void
call_unhandled_exception_delegate(MonoDomain * domain,MonoObject * delegate,MonoObject * exc)4520 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
4521 	MONO_REQ_GC_UNSAFE_MODE;
4522 
4523 	MonoError error;
4524 	MonoObject *e = NULL;
4525 	gpointer pa [2];
4526 	MonoDomain *current_domain = mono_domain_get ();
4527 
4528 	if (domain != current_domain)
4529 		mono_domain_set_internal_with_options (domain, FALSE);
4530 
4531 	g_assert (domain == mono_object_domain (domain->domain));
4532 
4533 	if (mono_object_domain (exc) != domain) {
4534 
4535 		exc = mono_object_xdomain_representation (exc, domain, &error);
4536 		if (!exc) {
4537 			if (!is_ok (&error)) {
4538 				MonoError inner_error;
4539 				MonoException *serialization_exc = mono_error_convert_to_exception (&error);
4540 				exc = mono_object_xdomain_representation ((MonoObject*)serialization_exc, domain, &inner_error);
4541 				mono_error_assert_ok (&inner_error);
4542 			} else {
4543 				exc = (MonoObject*) mono_exception_from_name_msg (mono_get_corlib (),
4544 						"System.Runtime.Serialization", "SerializationException",
4545 						"Could not serialize unhandled exception.");
4546 			}
4547 		}
4548 	}
4549 	g_assert (mono_object_domain (exc) == domain);
4550 
4551 	pa [0] = domain->domain;
4552 	pa [1] = create_unhandled_exception_eventargs (exc, &error);
4553 	mono_error_assert_ok (&error);
4554 	mono_runtime_delegate_try_invoke (delegate, pa, &e, &error);
4555 	if (!is_ok (&error)) {
4556 		if (e == NULL)
4557 			e = (MonoObject*)mono_error_convert_to_exception (&error);
4558 		else
4559 			mono_error_cleanup (&error);
4560 	}
4561 
4562 	if (domain != current_domain)
4563 		mono_domain_set_internal_with_options (current_domain, FALSE);
4564 
4565 	if (e) {
4566 		gchar *msg = mono_string_to_utf8_checked (((MonoException *) e)->message, &error);
4567 		if (!mono_error_ok (&error)) {
4568 			g_warning ("Exception inside UnhandledException handler with invalid message (Invalid characters)\n");
4569 			mono_error_cleanup (&error);
4570 		} else {
4571 			g_warning ("exception inside UnhandledException handler: %s\n", msg);
4572 			g_free (msg);
4573 		}
4574 	}
4575 }
4576 
4577 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANDLED_POLICY_CURRENT;
4578 
4579 /**
4580  * mono_runtime_unhandled_exception_policy_set:
4581  * \param policy the new policy
4582  * This is a VM internal routine.
4583  * Sets the runtime policy for handling unhandled exceptions.
4584  */
4585 void
mono_runtime_unhandled_exception_policy_set(MonoRuntimeUnhandledExceptionPolicy policy)4586 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
4587 	runtime_unhandled_exception_policy = policy;
4588 }
4589 
4590 /**
4591  * mono_runtime_unhandled_exception_policy_get:
4592  *
4593  * This is a VM internal routine.
4594  *
4595  * Gets the runtime policy for handling unhandled exceptions.
4596  */
4597 MonoRuntimeUnhandledExceptionPolicy
mono_runtime_unhandled_exception_policy_get(void)4598 mono_runtime_unhandled_exception_policy_get (void) {
4599 	return runtime_unhandled_exception_policy;
4600 }
4601 
4602 /**
4603  * mono_unhandled_exception:
4604  * \param exc exception thrown
4605  * This is a VM internal routine.
4606  *
4607  * We call this function when we detect an unhandled exception
4608  * in the default domain.
4609  *
4610  * It invokes the \c UnhandledException event in \c AppDomain or prints
4611  * a warning to the console
4612  */
4613 void
mono_unhandled_exception(MonoObject * exc_raw)4614 mono_unhandled_exception (MonoObject *exc_raw)
4615 {
4616 	MonoError error;
4617 	HANDLE_FUNCTION_ENTER ();
4618 	MONO_HANDLE_DCL (MonoObject, exc);
4619 	error_init (&error);
4620 	mono_unhandled_exception_checked (exc, &error);
4621 	mono_error_assert_ok (&error);
4622 	HANDLE_FUNCTION_RETURN ();
4623 }
4624 
4625 /**
4626  * mono_unhandled_exception:
4627  * @exc: exception thrown
4628  *
4629  * This is a VM internal routine.
4630  *
4631  * We call this function when we detect an unhandled exception
4632  * in the default domain.
4633  *
4634  * It invokes the * UnhandledException event in AppDomain or prints
4635  * a warning to the console
4636  */
4637 void
mono_unhandled_exception_checked(MonoObjectHandle exc,MonoError * error)4638 mono_unhandled_exception_checked (MonoObjectHandle exc, MonoError *error)
4639 {
4640 	MONO_REQ_GC_UNSAFE_MODE;
4641 
4642 	error_init (error);
4643 	MonoClassField *field;
4644 	MonoDomain *current_domain, *root_domain;
4645 	MonoObjectHandle current_appdomain_delegate = MONO_HANDLE_NEW (MonoObject, NULL);
4646 
4647 	MonoClass *klass = mono_handle_class (exc);
4648 	/*
4649 	 * AppDomainUnloadedException don't behave like unhandled exceptions unless thrown from
4650 	 * a thread started in unmanaged world.
4651 	 * https://msdn.microsoft.com/en-us/library/system.appdomainunloadedexception(v=vs.110).aspx#Anchor_6
4652 	 */
4653 	if (klass == mono_defaults.threadabortexception_class ||
4654 			(klass == mono_class_get_appdomain_unloaded_exception_class () &&
4655 			mono_thread_info_current ()->runtime_thread))
4656 		return;
4657 
4658 	field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "UnhandledException");
4659 	g_assert (field);
4660 
4661 	current_domain = mono_domain_get ();
4662 	root_domain = mono_get_root_domain ();
4663 
4664 	MonoObjectHandle root_appdomain_delegate = MONO_HANDLE_NEW (MonoObject, mono_field_get_value_object_checked (root_domain, field, (MonoObject*) root_domain->domain, error)); /* FIXME use handles for mono_field_get_value_object_checked */
4665 	return_if_nok (error);
4666 	if (current_domain != root_domain) {
4667 		MONO_HANDLE_ASSIGN (current_appdomain_delegate, MONO_HANDLE_NEW (MonoObject, mono_field_get_value_object_checked (current_domain, field, (MonoObject*) current_domain->domain, error))); /* FIXME use handles for mono_field_get_value_object_checked */
4668 		return_if_nok (error);
4669 	}
4670 
4671 	if (MONO_HANDLE_IS_NULL (current_appdomain_delegate) && MONO_HANDLE_IS_NULL (root_appdomain_delegate)) {
4672 		mono_print_unhandled_exception (MONO_HANDLE_RAW (exc)); /* FIXME use handles for mono_print_unhandled_exception */
4673 	} else {
4674 		/* unhandled exception callbacks must not be aborted */
4675 		mono_threads_begin_abort_protected_block ();
4676 		if (!MONO_HANDLE_IS_NULL (root_appdomain_delegate))
4677 			call_unhandled_exception_delegate (root_domain, MONO_HANDLE_RAW (root_appdomain_delegate), MONO_HANDLE_RAW (exc)); /* FIXME use handles in call_unhandled_exception_delegate */
4678 		if (!MONO_HANDLE_IS_NULL (current_appdomain_delegate))
4679 			call_unhandled_exception_delegate (current_domain, MONO_HANDLE_RAW (current_appdomain_delegate), MONO_HANDLE_RAW (exc));
4680 		mono_threads_end_abort_protected_block ();
4681 	}
4682 
4683 	/* set exitcode only if we will abort the process */
4684 	if ((main_thread && mono_thread_internal_current () == main_thread->internal_thread)
4685 		 || mono_runtime_unhandled_exception_policy_get () == MONO_UNHANDLED_POLICY_CURRENT)
4686 	{
4687 		mono_environment_exitcode_set (1);
4688 	}
4689 }
4690 
4691 /**
4692  * mono_runtime_exec_managed_code:
4693  * \param domain Application domain
4694  * \param main_func function to invoke from the execution thread
4695  * \param main_args parameter to the main_func
4696  * Launch a new thread to execute a function
4697  *
4698  * \p main_func is called back from the thread with main_args as the
4699  * parameter.  The callback function is expected to start \c Main
4700  * eventually.  This function then waits for all managed threads to
4701  * finish.
4702  * It is not necessary anymore to execute managed code in a subthread,
4703  * so this function should not be used anymore by default: just
4704  * execute the code and then call mono_thread_manage().
4705  */
4706 void
mono_runtime_exec_managed_code(MonoDomain * domain,MonoMainThreadFunc main_func,gpointer main_args)4707 mono_runtime_exec_managed_code (MonoDomain *domain,
4708 				MonoMainThreadFunc main_func,
4709 				gpointer main_args)
4710 {
4711 	MonoError error;
4712 	mono_thread_create_checked (domain, main_func, main_args, &error);
4713 	mono_error_assert_ok (&error);
4714 
4715 	mono_thread_manage ();
4716 }
4717 
4718 static void
prepare_thread_to_exec_main(MonoDomain * domain,MonoMethod * method)4719 prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
4720 {
4721 	MonoInternalThread* thread = mono_thread_internal_current ();
4722 	MonoCustomAttrInfo* cinfo;
4723 	gboolean has_stathread_attribute;
4724 
4725 	if (!domain->entry_assembly) {
4726 		gchar *str;
4727 		MonoError error;
4728 		MonoAssembly *assembly;
4729 
4730 		assembly = method->klass->image->assembly;
4731 		domain->entry_assembly = assembly;
4732 		/* Domains created from another domain already have application_base and configuration_file set */
4733 		if (domain->setup->application_base == NULL) {
4734 			MonoString *basedir = mono_string_new_checked (domain, assembly->basedir, &error);
4735 			mono_error_assert_ok (&error);
4736 			MONO_OBJECT_SETREF (domain->setup, application_base, basedir);
4737 		}
4738 
4739 		if (domain->setup->configuration_file == NULL) {
4740 			str = g_strconcat (assembly->image->name, ".config", NULL);
4741 			MonoString *config_file = mono_string_new_checked (domain, str, &error);
4742 			mono_error_assert_ok (&error);
4743 			MONO_OBJECT_SETREF (domain->setup, configuration_file, config_file);
4744 			g_free (str);
4745 			mono_domain_set_options_from_config (domain);
4746 		}
4747 	}
4748 
4749 	MonoError cattr_error;
4750 	cinfo = mono_custom_attrs_from_method_checked (method, &cattr_error);
4751 	mono_error_cleanup (&cattr_error); /* FIXME warn here? */
4752 	if (cinfo) {
4753 		has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, mono_class_get_sta_thread_attribute_class ());
4754 		if (!cinfo->cached)
4755 			mono_custom_attrs_free (cinfo);
4756 	} else {
4757 		has_stathread_attribute = FALSE;
4758  	}
4759 	if (has_stathread_attribute) {
4760 		thread->apartment_state = ThreadApartmentState_STA;
4761 	} else {
4762 		thread->apartment_state = ThreadApartmentState_MTA;
4763 	}
4764 	mono_thread_init_apartment_state ();
4765 
4766 }
4767 
4768 static int
do_exec_main_checked(MonoMethod * method,MonoArray * args,MonoError * error)4769 do_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4770 {
4771 	MONO_REQ_GC_UNSAFE_MODE;
4772 
4773 	gpointer pa [1];
4774 	int rval;
4775 
4776 	error_init (error);
4777 	g_assert (args);
4778 
4779 	pa [0] = args;
4780 
4781 	/* FIXME: check signature of method */
4782 	if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4783 		MonoObject *res;
4784 		res = mono_runtime_invoke_checked (method, NULL, pa, error);
4785 		if (is_ok (error))
4786 			rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4787 		else
4788 			rval = -1;
4789 		mono_environment_exitcode_set (rval);
4790 	} else {
4791 		mono_runtime_invoke_checked (method, NULL, pa, error);
4792 
4793 		if (is_ok (error))
4794 			rval = 0;
4795 		else {
4796 			rval = -1;
4797 		}
4798 	}
4799 	return rval;
4800 }
4801 
4802 static int
do_try_exec_main(MonoMethod * method,MonoArray * args,MonoObject ** exc)4803 do_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4804 {
4805 	MONO_REQ_GC_UNSAFE_MODE;
4806 
4807 	gpointer pa [1];
4808 	int rval;
4809 
4810 	g_assert (args);
4811 	g_assert (exc);
4812 
4813 	pa [0] = args;
4814 
4815 	/* FIXME: check signature of method */
4816 	if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
4817 		MonoError inner_error;
4818 		MonoObject *res;
4819 		res = mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4820 		if (*exc == NULL && !mono_error_ok (&inner_error))
4821 			*exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4822 		else
4823 			mono_error_cleanup (&inner_error);
4824 
4825 		if (*exc == NULL)
4826 			rval = *(guint32 *)((char *)res + sizeof (MonoObject));
4827 		else
4828 			rval = -1;
4829 
4830 		mono_environment_exitcode_set (rval);
4831 	} else {
4832 		MonoError inner_error;
4833 		mono_runtime_try_invoke (method, NULL, pa, exc, &inner_error);
4834 		if (*exc == NULL && !mono_error_ok (&inner_error))
4835 			*exc = (MonoObject*) mono_error_convert_to_exception (&inner_error);
4836 		else
4837 			mono_error_cleanup (&inner_error);
4838 
4839 		if (*exc == NULL)
4840 			rval = 0;
4841 		else {
4842 			/* If the return type of Main is void, only
4843 			 * set the exitcode if an exception was thrown
4844 			 * (we don't want to blow away an
4845 			 * explicitly-set exit code)
4846 			 */
4847 			rval = -1;
4848 			mono_environment_exitcode_set (rval);
4849 		}
4850 	}
4851 
4852 	return rval;
4853 }
4854 
4855 /*
4856  * Execute a standard Main() method (args doesn't contain the
4857  * executable name).
4858  */
4859 int
mono_runtime_exec_main(MonoMethod * method,MonoArray * args,MonoObject ** exc)4860 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4861 {
4862 	MonoError error;
4863 	prepare_thread_to_exec_main (mono_object_domain (args), method);
4864 	if (exc) {
4865 		int rval = do_try_exec_main (method, args, exc);
4866 		return rval;
4867 	} else {
4868 		int rval = do_exec_main_checked (method, args, &error);
4869 		mono_error_raise_exception_deprecated (&error); /* OK to throw, external only with no better option */
4870 		return rval;
4871 	}
4872 }
4873 
4874 /*
4875  * Execute a standard Main() method (args doesn't contain the
4876  * executable name).
4877  *
4878  * On failure sets @error
4879  */
4880 int
mono_runtime_exec_main_checked(MonoMethod * method,MonoArray * args,MonoError * error)4881 mono_runtime_exec_main_checked (MonoMethod *method, MonoArray *args, MonoError *error)
4882 {
4883 	error_init (error);
4884 	prepare_thread_to_exec_main (mono_object_domain (args), method);
4885 	return do_exec_main_checked (method, args, error);
4886 }
4887 
4888 /*
4889  * Execute a standard Main() method (args doesn't contain the
4890  * executable name).
4891  *
4892  * On failure sets @error if Main couldn't be executed, or @exc if it threw an exception.
4893  */
4894 int
mono_runtime_try_exec_main(MonoMethod * method,MonoArray * args,MonoObject ** exc)4895 mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
4896 {
4897 	prepare_thread_to_exec_main (mono_object_domain (args), method);
4898 	return do_try_exec_main (method, args, exc);
4899 }
4900 
4901 
4902 
4903 /** invoke_array_extract_argument:
4904  * @params: array of arguments to the method.
4905  * @i: the index of the argument to extract.
4906  * @t: ith type from the method signature.
4907  * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument
4908  * @error: set on error.
4909  *
4910  * Given an array of method arguments, return the ith one using the corresponding type
4911  * to perform necessary unboxing.  If method expects a ref nullable argument, writes TRUE to @has_byref_nullables.
4912  *
4913  * On failure sets @error and returns NULL.
4914  */
4915 static gpointer
invoke_array_extract_argument(MonoArray * params,int i,MonoType * t,gboolean * has_byref_nullables,MonoError * error)4916 invoke_array_extract_argument (MonoArray *params, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error)
4917 {
4918 	MonoType *t_orig = t;
4919 	gpointer result = NULL;
4920 	error_init (error);
4921 		again:
4922 			switch (t->type) {
4923 			case MONO_TYPE_U1:
4924 			case MONO_TYPE_I1:
4925 			case MONO_TYPE_BOOLEAN:
4926 			case MONO_TYPE_U2:
4927 			case MONO_TYPE_I2:
4928 			case MONO_TYPE_CHAR:
4929 			case MONO_TYPE_U:
4930 			case MONO_TYPE_I:
4931 			case MONO_TYPE_U4:
4932 			case MONO_TYPE_I4:
4933 			case MONO_TYPE_U8:
4934 			case MONO_TYPE_I8:
4935 			case MONO_TYPE_R4:
4936 			case MONO_TYPE_R8:
4937 			case MONO_TYPE_VALUETYPE:
4938 				if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (t_orig))) {
4939 					/* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */
4940 					result = mono_array_get (params, MonoObject*, i);
4941 					if (t->byref)
4942 						*has_byref_nullables = TRUE;
4943 				} else {
4944 					/* MS seems to create the objects if a null is passed in */
4945 					gboolean was_null = FALSE;
4946 					if (!mono_array_get (params, MonoObject*, i)) {
4947 						MonoObject *o = mono_object_new_checked (mono_domain_get (), mono_class_from_mono_type (t_orig), error);
4948 						return_val_if_nok (error, NULL);
4949 						mono_array_setref (params, i, o);
4950 						was_null = TRUE;
4951 					}
4952 
4953 					if (t->byref) {
4954 						/*
4955 						 * We can't pass the unboxed vtype byref to the callee, since
4956 						 * that would mean the callee would be able to modify boxed
4957 						 * primitive types. So we (and MS) make a copy of the boxed
4958 						 * object, pass that to the callee, and replace the original
4959 						 * boxed object in the arg array with the copy.
4960 						 */
4961 						MonoObject *orig = mono_array_get (params, MonoObject*, i);
4962 						MonoObject *copy = mono_value_box_checked (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig), error);
4963 						return_val_if_nok (error, NULL);
4964 						mono_array_setref (params, i, copy);
4965 					}
4966 
4967 					result = mono_object_unbox (mono_array_get (params, MonoObject*, i));
4968 					if (!t->byref && was_null)
4969 						mono_array_setref (params, i, NULL);
4970 				}
4971 				break;
4972 			case MONO_TYPE_STRING:
4973 			case MONO_TYPE_OBJECT:
4974 			case MONO_TYPE_CLASS:
4975 			case MONO_TYPE_ARRAY:
4976 			case MONO_TYPE_SZARRAY:
4977 				if (t->byref)
4978 					result = mono_array_addr (params, MonoObject*, i);
4979 					// FIXME: I need to check this code path
4980 				else
4981 					result = mono_array_get (params, MonoObject*, i);
4982 				break;
4983 			case MONO_TYPE_GENERICINST:
4984 				if (t->byref)
4985 					t = &t->data.generic_class->container_class->this_arg;
4986 				else
4987 					t = &t->data.generic_class->container_class->byval_arg;
4988 				goto again;
4989 			case MONO_TYPE_PTR: {
4990 				MonoObject *arg;
4991 
4992 				/* The argument should be an IntPtr */
4993 				arg = mono_array_get (params, MonoObject*, i);
4994 				if (arg == NULL) {
4995 					result = NULL;
4996 				} else {
4997 					g_assert (arg->vtable->klass == mono_defaults.int_class);
4998 					result = ((MonoIntPtr*)arg)->m_value;
4999 				}
5000 				break;
5001 			}
5002 			default:
5003 				g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type);
5004 			}
5005 	return result;
5006 }
5007 /**
5008  * mono_runtime_invoke_array:
5009  * \param method method to invoke
5010  * \param obj object instance
5011  * \param params arguments to the method
5012  * \param exc exception information.
5013  * Invokes the method represented by \p method on the object \p obj.
5014  *
5015  * \p obj is the \c this pointer, it should be NULL for static
5016  * methods, a \c MonoObject* for object instances and a pointer to
5017  * the value type for value types.
5018  *
5019  * The \p params array contains the arguments to the method with the
5020  * same convention: \c MonoObject* pointers for object instances and
5021  * pointers to the value type otherwise. The \c _invoke_array
5022  * variant takes a C# \c object[] as the params argument (\c MonoArray*):
5023  * in this case the value types are boxed inside the
5024  * respective reference representation.
5025  *
5026  * From unmanaged code you'll usually use the
5027  * mono_runtime_invoke_checked() variant.
5028  *
5029  * Note that this function doesn't handle virtual methods for
5030  * you, it will exec the exact method you pass: we still need to
5031  * expose a function to lookup the derived class implementation
5032  * of a virtual method (there are examples of this in the code,
5033  * though).
5034  *
5035  * You can pass NULL as the \p exc argument if you don't want to
5036  * catch exceptions, otherwise, \c *exc will be set to the exception
5037  * thrown, if any.  if an exception is thrown, you can't use the
5038  * \c MonoObject* result from the function.
5039  *
5040  * If the method returns a value type, it is boxed in an object
5041  * reference.
5042  */
5043 MonoObject*
mono_runtime_invoke_array(MonoMethod * method,void * obj,MonoArray * params,MonoObject ** exc)5044 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5045 			   MonoObject **exc)
5046 {
5047 	MonoError error;
5048 	if (exc) {
5049 		MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, exc, &error);
5050 		if (*exc) {
5051 			mono_error_cleanup (&error);
5052 			return NULL;
5053 		} else {
5054 			if (!is_ok (&error))
5055 				*exc = (MonoObject*)mono_error_convert_to_exception (&error);
5056 			return result;
5057 		}
5058 	} else {
5059 		MonoObject *result = mono_runtime_try_invoke_array (method, obj, params, NULL, &error);
5060 		mono_error_raise_exception_deprecated (&error); /* OK to throw, external only without a good alternative */
5061 		return result;
5062 	}
5063 }
5064 
5065 /**
5066  * mono_runtime_invoke_array_checked:
5067  * \param method method to invoke
5068  * \param obj object instance
5069  * \param params arguments to the method
5070  * \param error set on failure.
5071  * Invokes the method represented by \p method on the object \p obj.
5072  *
5073  * \p obj is the \c this pointer, it should be NULL for static
5074  * methods, a \c MonoObject* for object instances and a pointer to
5075  * the value type for value types.
5076  *
5077  * The \p params array contains the arguments to the method with the
5078  * same convention: \c MonoObject* pointers for object instances and
5079  * pointers to the value type otherwise. The \c _invoke_array
5080  * variant takes a C# \c object[] as the \p params argument (\c MonoArray*):
5081  * in this case the value types are boxed inside the
5082  * respective reference representation.
5083  *
5084  * From unmanaged code you'll usually use the
5085  * mono_runtime_invoke_checked() variant.
5086  *
5087  * Note that this function doesn't handle virtual methods for
5088  * you, it will exec the exact method you pass: we still need to
5089  * expose a function to lookup the derived class implementation
5090  * of a virtual method (there are examples of this in the code,
5091  * though).
5092  *
5093  * On failure or exception, \p error will be set. In that case, you
5094  * can't use the \c MonoObject* result from the function.
5095  *
5096  * If the method returns a value type, it is boxed in an object
5097  * reference.
5098  */
5099 MonoObject*
mono_runtime_invoke_array_checked(MonoMethod * method,void * obj,MonoArray * params,MonoError * error)5100 mono_runtime_invoke_array_checked (MonoMethod *method, void *obj, MonoArray *params,
5101 				   MonoError *error)
5102 {
5103 	error_init (error);
5104 	return mono_runtime_try_invoke_array (method, obj, params, NULL, error);
5105 }
5106 
5107 /**
5108  * mono_runtime_try_invoke_array:
5109  * \param method method to invoke
5110  * \param obj object instance
5111  * \param params arguments to the method
5112  * \param exc exception information.
5113  * \param error set on failure.
5114  * Invokes the method represented by \p method on the object \p obj.
5115  *
5116  * \p obj is the \c this pointer, it should be NULL for static
5117  * methods, a \c MonoObject* for object instances and a pointer to
5118  * the value type for value types.
5119  *
5120  * The \p params array contains the arguments to the method with the
5121  * same convention: \c MonoObject* pointers for object instances and
5122  * pointers to the value type otherwise. The \c _invoke_array
5123  * variant takes a C# \c object[] as the params argument (\c MonoArray*):
5124  * in this case the value types are boxed inside the
5125  * respective reference representation.
5126  *
5127  * From unmanaged code you'll usually use the
5128  * mono_runtime_invoke_checked() variant.
5129  *
5130  * Note that this function doesn't handle virtual methods for
5131  * you, it will exec the exact method you pass: we still need to
5132  * expose a function to lookup the derived class implementation
5133  * of a virtual method (there are examples of this in the code,
5134  * though).
5135  *
5136  * You can pass NULL as the \p exc argument if you don't want to catch
5137  * exceptions, otherwise, \c *exc will be set to the exception thrown, if
5138  * any.  On other failures, \p error will be set. If an exception is
5139  * thrown or there's an error, you can't use the \c MonoObject* result
5140  * from the function.
5141  *
5142  * If the method returns a value type, it is boxed in an object
5143  * reference.
5144  */
5145 MonoObject*
mono_runtime_try_invoke_array(MonoMethod * method,void * obj,MonoArray * params,MonoObject ** exc,MonoError * error)5146 mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
5147 			       MonoObject **exc, MonoError *error)
5148 {
5149 	MONO_REQ_GC_UNSAFE_MODE;
5150 
5151 	error_init (error);
5152 
5153 	MonoMethodSignature *sig = mono_method_signature (method);
5154 	gpointer *pa = NULL;
5155 	MonoObject *res;
5156 	int i;
5157 	gboolean has_byref_nullables = FALSE;
5158 
5159 	if (NULL != params) {
5160 		pa = (void **)alloca (sizeof (gpointer) * mono_array_length (params));
5161 		for (i = 0; i < mono_array_length (params); i++) {
5162 			MonoType *t = sig->params [i];
5163 			pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error);
5164 			return_val_if_nok (error, NULL);
5165 		}
5166 	}
5167 
5168 	if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
5169 		void *o = obj;
5170 
5171 		if (mono_class_is_nullable (method->klass)) {
5172 			/* Need to create a boxed vtype instead */
5173 			g_assert (!obj);
5174 
5175 			if (!params)
5176 				return NULL;
5177 			else {
5178 				return mono_value_box_checked (mono_domain_get (), method->klass->cast_class, pa [0], error);
5179 			}
5180 		}
5181 
5182 		if (!obj) {
5183 			obj = mono_object_new_checked (mono_domain_get (), method->klass, error);
5184 			mono_error_assert_ok (error);
5185 			g_assert (obj); /*maybe we should raise a TLE instead?*/
5186 #ifndef DISABLE_REMOTING
5187 			if (mono_object_is_transparent_proxy (obj)) {
5188 				method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
5189 			}
5190 #endif
5191 			if (method->klass->valuetype)
5192 				o = (MonoObject *)mono_object_unbox ((MonoObject *)obj);
5193 			else
5194 				o = obj;
5195 		} else if (method->klass->valuetype) {
5196 			obj = mono_value_box_checked (mono_domain_get (), method->klass, obj, error);
5197 			return_val_if_nok (error, NULL);
5198 		}
5199 
5200 		if (exc) {
5201 			mono_runtime_try_invoke (method, o, pa, exc, error);
5202 		} else {
5203 			mono_runtime_invoke_checked (method, o, pa, error);
5204 		}
5205 
5206 		return (MonoObject *)obj;
5207 	} else {
5208 		if (mono_class_is_nullable (method->klass)) {
5209 			MonoObject *nullable;
5210 
5211 			/* Convert the unboxed vtype into a Nullable structure */
5212 			nullable = mono_object_new_checked (mono_domain_get (), method->klass, error);
5213 			return_val_if_nok (error, NULL);
5214 
5215 			MonoObject *boxed = mono_value_box_checked (mono_domain_get (), method->klass->cast_class, obj, error);
5216 			return_val_if_nok (error, NULL);
5217 			mono_nullable_init ((guint8 *)mono_object_unbox (nullable), boxed, method->klass);
5218 			obj = mono_object_unbox (nullable);
5219 		}
5220 
5221 		/* obj must be already unboxed if needed */
5222 		if (exc) {
5223 			res = mono_runtime_try_invoke (method, obj, pa, exc, error);
5224 		} else {
5225 			res = mono_runtime_invoke_checked (method, obj, pa, error);
5226 		}
5227 		return_val_if_nok (error, NULL);
5228 
5229 		if (sig->ret->type == MONO_TYPE_PTR) {
5230 			MonoClass *pointer_class;
5231 			static MonoMethod *box_method;
5232 			void *box_args [2];
5233 			MonoObject *box_exc;
5234 
5235 			/*
5236 			 * The runtime-invoke wrapper returns a boxed IntPtr, need to
5237 			 * convert it to a Pointer object.
5238 			 */
5239 			pointer_class = mono_class_get_pointer_class ();
5240 			if (!box_method)
5241 				box_method = mono_class_get_method_from_name (pointer_class, "Box", -1);
5242 
5243 			g_assert (res->vtable->klass == mono_defaults.int_class);
5244 			box_args [0] = ((MonoIntPtr*)res)->m_value;
5245 			box_args [1] = mono_type_get_object_checked (mono_domain_get (), sig->ret, error);
5246 			return_val_if_nok (error, NULL);
5247 
5248 			res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error);
5249 			g_assert (box_exc == NULL);
5250 			mono_error_assert_ok (error);
5251 		}
5252 
5253 		if (has_byref_nullables) {
5254 			/*
5255 			 * The runtime invoke wrapper already converted byref nullables back,
5256 			 * and stored them in pa, we just need to copy them back to the
5257 			 * managed array.
5258 			 */
5259 			for (i = 0; i < mono_array_length (params); i++) {
5260 				MonoType *t = sig->params [i];
5261 
5262 				if (t->byref && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t)))
5263 					mono_array_setref (params, i, pa [i]);
5264 			}
5265 		}
5266 
5267 		return res;
5268 	}
5269 }
5270 
5271 /**
5272  * mono_object_new:
5273  * \param klass the class of the object that we want to create
5274  * \returns a newly created object whose definition is
5275  * looked up using \p klass.   This will not invoke any constructors,
5276  * so the consumer of this routine has to invoke any constructors on
5277  * its own to initialize the object.
5278  *
5279  * It returns NULL on failure.
5280  */
5281 MonoObject *
mono_object_new(MonoDomain * domain,MonoClass * klass)5282 mono_object_new (MonoDomain *domain, MonoClass *klass)
5283 {
5284 	MONO_REQ_GC_UNSAFE_MODE;
5285 
5286 	MonoError error;
5287 
5288 	MonoObject * result = mono_object_new_checked (domain, klass, &error);
5289 
5290 	mono_error_cleanup (&error);
5291 	return result;
5292 }
5293 
5294 MonoObject *
ves_icall_object_new(MonoDomain * domain,MonoClass * klass)5295 ves_icall_object_new (MonoDomain *domain, MonoClass *klass)
5296 {
5297 	MONO_REQ_GC_UNSAFE_MODE;
5298 
5299 	MonoError error;
5300 
5301 	MonoObject * result = mono_object_new_checked (domain, klass, &error);
5302 
5303 	mono_error_set_pending_exception (&error);
5304 	return result;
5305 }
5306 
5307 /**
5308  * mono_object_new_checked:
5309  * \param klass the class of the object that we want to create
5310  * \param error set on error
5311  * \returns a newly created object whose definition is
5312  * looked up using \p klass.   This will not invoke any constructors,
5313  * so the consumer of this routine has to invoke any constructors on
5314  * its own to initialize the object.
5315  *
5316  * It returns NULL on failure and sets \p error.
5317  */
5318 MonoObject *
mono_object_new_checked(MonoDomain * domain,MonoClass * klass,MonoError * error)5319 mono_object_new_checked (MonoDomain *domain, MonoClass *klass, MonoError *error)
5320 {
5321 	MONO_REQ_GC_UNSAFE_MODE;
5322 
5323 	MonoVTable *vtable;
5324 
5325 	vtable = mono_class_vtable_full (domain, klass, error);
5326 	if (!is_ok (error))
5327 		return NULL;
5328 
5329 	MonoObject *o = mono_object_new_specific_checked (vtable, error);
5330 	return o;
5331 }
5332 
5333 /**
5334  * mono_object_new_pinned:
5335  *
5336  *   Same as mono_object_new, but the returned object will be pinned.
5337  * For SGEN, these objects will only be freed at appdomain unload.
5338  */
5339 MonoObject *
mono_object_new_pinned(MonoDomain * domain,MonoClass * klass,MonoError * error)5340 mono_object_new_pinned (MonoDomain *domain, MonoClass *klass, MonoError *error)
5341 {
5342 	MONO_REQ_GC_UNSAFE_MODE;
5343 
5344 	MonoVTable *vtable;
5345 
5346 	error_init (error);
5347 
5348 	vtable = mono_class_vtable (domain, klass);
5349 	g_assert (vtable); /* FIXME don't swallow the error */
5350 
5351 	MonoObject *o = (MonoObject *)mono_gc_alloc_pinned_obj (vtable, mono_class_instance_size (klass));
5352 
5353 	if (G_UNLIKELY (!o))
5354 		mono_error_set_out_of_memory (error, "Could not allocate %i bytes", mono_class_instance_size (klass));
5355 	else if (G_UNLIKELY (vtable->klass->has_finalize))
5356 		mono_object_register_finalizer (o);
5357 
5358 	return o;
5359 }
5360 
5361 /**
5362  * mono_object_new_specific:
5363  * \param vtable the vtable of the object that we want to create
5364  * \returns A newly created object with class and domain specified
5365  * by \p vtable
5366  */
5367 MonoObject *
mono_object_new_specific(MonoVTable * vtable)5368 mono_object_new_specific (MonoVTable *vtable)
5369 {
5370 	MonoError error;
5371 	MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5372 	mono_error_cleanup (&error);
5373 
5374 	return o;
5375 }
5376 
5377 MonoObject *
mono_object_new_specific_checked(MonoVTable * vtable,MonoError * error)5378 mono_object_new_specific_checked (MonoVTable *vtable, MonoError *error)
5379 {
5380 	MONO_REQ_GC_UNSAFE_MODE;
5381 
5382 	MonoObject *o;
5383 
5384 	error_init (error);
5385 
5386 	/* check for is_com_object for COM Interop */
5387 	if (mono_vtable_is_remote (vtable) || mono_class_is_com_object (vtable->klass))
5388 	{
5389 		gpointer pa [1];
5390 		MonoMethod *im = vtable->domain->create_proxy_for_type_method;
5391 
5392 		if (im == NULL) {
5393 			MonoClass *klass = mono_class_get_activation_services_class ();
5394 
5395 			if (!klass->inited)
5396 				mono_class_init (klass);
5397 
5398 			im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
5399 			if (!im) {
5400 				mono_error_set_not_supported (error, "Linked away.");
5401 				return NULL;
5402 			}
5403 			vtable->domain->create_proxy_for_type_method = im;
5404 		}
5405 
5406 		pa [0] = mono_type_get_object_checked (mono_domain_get (), &vtable->klass->byval_arg, error);
5407 		if (!mono_error_ok (error))
5408 			return NULL;
5409 
5410 		o = mono_runtime_invoke_checked (im, NULL, pa, error);
5411 		if (!mono_error_ok (error))
5412 			return NULL;
5413 
5414 		if (o != NULL)
5415 			return o;
5416 	}
5417 
5418 	return mono_object_new_alloc_specific_checked (vtable, error);
5419 }
5420 
5421 MonoObject *
ves_icall_object_new_specific(MonoVTable * vtable)5422 ves_icall_object_new_specific (MonoVTable *vtable)
5423 {
5424 	MonoError error;
5425 	MonoObject *o = mono_object_new_specific_checked (vtable, &error);
5426 	mono_error_set_pending_exception (&error);
5427 
5428 	return o;
5429 }
5430 
5431 /**
5432  * mono_object_new_alloc_specific:
5433  * \param vtable virtual table for the object.
5434  * This function allocates a new \c MonoObject with the type derived
5435  * from the \p vtable information.   If the class of this object has a
5436  * finalizer, then the object will be tracked for finalization.
5437  *
5438  * This method might raise an exception on errors.  Use the
5439  * \c mono_object_new_fast_checked method if you want to manually raise
5440  * the exception.
5441  *
5442  * \returns the allocated object.
5443  */
5444 MonoObject *
mono_object_new_alloc_specific(MonoVTable * vtable)5445 mono_object_new_alloc_specific (MonoVTable *vtable)
5446 {
5447 	MonoError error;
5448 	MonoObject *o = mono_object_new_alloc_specific_checked (vtable, &error);
5449 	mono_error_cleanup (&error);
5450 
5451 	return o;
5452 }
5453 
5454 /**
5455  * mono_object_new_alloc_specific_checked:
5456  * \param vtable virtual table for the object.
5457  * \param error holds the error return value.
5458  *
5459  * This function allocates a new \c MonoObject with the type derived
5460  * from the \p vtable information. If the class of this object has a
5461  * finalizer, then the object will be tracked for finalization.
5462  *
5463  * If there is not enough memory, the \p error parameter will be set
5464  * and will contain a user-visible message with the amount of bytes
5465  * that were requested.
5466  *
5467  * \returns the allocated object, or NULL if there is not enough memory
5468  */
5469 MonoObject *
mono_object_new_alloc_specific_checked(MonoVTable * vtable,MonoError * error)5470 mono_object_new_alloc_specific_checked (MonoVTable *vtable, MonoError *error)
5471 {
5472 	MONO_REQ_GC_UNSAFE_MODE;
5473 
5474 	MonoObject *o;
5475 
5476 	error_init (error);
5477 
5478 	o = (MonoObject *)mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5479 
5480 	if (G_UNLIKELY (!o))
5481 		mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5482 	else if (G_UNLIKELY (vtable->klass->has_finalize || vtable->klass->has_weak_fields)) {
5483 		if (vtable->klass->has_finalize)
5484 			mono_object_register_finalizer (o);
5485 		if (vtable->klass->has_weak_fields)
5486 			mono_gc_register_obj_with_weak_fields (o);
5487 	}
5488 
5489 	return o;
5490 }
5491 
5492 /**
5493  * mono_object_new_fast:
5494  * \param vtable virtual table for the object.
5495  *
5496  * This function allocates a new \c MonoObject with the type derived
5497  * from the \p vtable information.   The returned object is not tracked
5498  * for finalization.   If your object implements a finalizer, you should
5499  * use \c mono_object_new_alloc_specific instead.
5500  *
5501  * This method might raise an exception on errors.  Use the
5502  * \c mono_object_new_fast_checked method if you want to manually raise
5503  * the exception.
5504  *
5505  * \returns the allocated object.
5506  */
5507 MonoObject*
mono_object_new_fast(MonoVTable * vtable)5508 mono_object_new_fast (MonoVTable *vtable)
5509 {
5510 	MonoError error;
5511 	MonoObject *o = mono_object_new_fast_checked (vtable, &error);
5512 	mono_error_cleanup (&error);
5513 
5514 	return o;
5515 }
5516 
5517 /**
5518  * mono_object_new_fast_checked:
5519  * \param vtable virtual table for the object.
5520  * \param error holds the error return value.
5521  *
5522  * This function allocates a new \c MonoObject with the type derived
5523  * from the \p vtable information. The returned object is not tracked
5524  * for finalization.   If your object implements a finalizer, you should
5525  * use \c mono_object_new_alloc_specific_checked instead.
5526  *
5527  * If there is not enough memory, the \p error parameter will be set
5528  * and will contain a user-visible message with the amount of bytes
5529  * that were requested.
5530  *
5531  * \returns the allocated object, or NULL if there is not enough memory
5532  */
5533 MonoObject*
mono_object_new_fast_checked(MonoVTable * vtable,MonoError * error)5534 mono_object_new_fast_checked (MonoVTable *vtable, MonoError *error)
5535 {
5536 	MONO_REQ_GC_UNSAFE_MODE;
5537 
5538 	MonoObject *o;
5539 
5540 	error_init (error);
5541 
5542 	o = mono_gc_alloc_obj (vtable, vtable->klass->instance_size);
5543 
5544 	if (G_UNLIKELY (!o))
5545 		mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5546 
5547 	return o;
5548 }
5549 
5550 MonoObject*
mono_object_new_mature(MonoVTable * vtable,MonoError * error)5551 mono_object_new_mature (MonoVTable *vtable, MonoError *error)
5552 {
5553 	MONO_REQ_GC_UNSAFE_MODE;
5554 
5555 	MonoObject *o;
5556 
5557 	error_init (error);
5558 
5559 	o = mono_gc_alloc_mature (vtable, vtable->klass->instance_size);
5560 
5561 	if (G_UNLIKELY (!o))
5562 		mono_error_set_out_of_memory (error, "Could not allocate %i bytes", vtable->klass->instance_size);
5563 	else if (G_UNLIKELY (vtable->klass->has_finalize))
5564 		mono_object_register_finalizer (o);
5565 
5566 	return o;
5567 }
5568 
5569 /**
5570  * mono_object_new_from_token:
5571  * \param image Context where the type_token is hosted
5572  * \param token a token of the type that we want to create
5573  * \returns A newly created object whose definition is
5574  * looked up using \p token in the \p image image
5575  */
5576 MonoObject *
mono_object_new_from_token(MonoDomain * domain,MonoImage * image,guint32 token)5577 mono_object_new_from_token  (MonoDomain *domain, MonoImage *image, guint32 token)
5578 {
5579 	MONO_REQ_GC_UNSAFE_MODE;
5580 
5581 	MonoError error;
5582 	MonoObject *result;
5583 	MonoClass *klass;
5584 
5585 	klass = mono_class_get_checked (image, token, &error);
5586 	mono_error_assert_ok (&error);
5587 
5588 	result = mono_object_new_checked (domain, klass, &error);
5589 
5590 	mono_error_cleanup (&error);
5591 	return result;
5592 
5593 }
5594 
5595 
5596 /**
5597  * mono_object_clone:
5598  * \param obj the object to clone
5599  * \returns A newly created object who is a shallow copy of \p obj
5600  */
5601 MonoObject *
mono_object_clone(MonoObject * obj)5602 mono_object_clone (MonoObject *obj)
5603 {
5604 	MonoError error;
5605 	MonoObject *o = mono_object_clone_checked (obj, &error);
5606 	mono_error_cleanup (&error);
5607 
5608 	return o;
5609 }
5610 
5611 MonoObject *
mono_object_clone_checked(MonoObject * obj,MonoError * error)5612 mono_object_clone_checked (MonoObject *obj, MonoError *error)
5613 {
5614 	MONO_REQ_GC_UNSAFE_MODE;
5615 
5616 	MonoObject *o;
5617 	int size;
5618 
5619 	error_init (error);
5620 
5621 	size = obj->vtable->klass->instance_size;
5622 
5623 	if (obj->vtable->klass->rank)
5624 		return (MonoObject*)mono_array_clone_checked ((MonoArray*)obj, error);
5625 
5626 	o = (MonoObject *)mono_gc_alloc_obj (obj->vtable, size);
5627 
5628 	if (G_UNLIKELY (!o)) {
5629 		mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5630 		return NULL;
5631 	}
5632 
5633 	/* If the object doesn't contain references this will do a simple memmove. */
5634 	mono_gc_wbarrier_object_copy (o, obj);
5635 
5636 	if (obj->vtable->klass->has_finalize)
5637 		mono_object_register_finalizer (o);
5638 	return o;
5639 }
5640 
5641 /**
5642  * mono_array_full_copy:
5643  * \param src source array to copy
5644  * \param dest destination array
5645  * Copies the content of one array to another with exactly the same type and size.
5646  */
5647 void
mono_array_full_copy(MonoArray * src,MonoArray * dest)5648 mono_array_full_copy (MonoArray *src, MonoArray *dest)
5649 {
5650 	MONO_REQ_GC_UNSAFE_MODE;
5651 
5652 	uintptr_t size;
5653 	MonoClass *klass = src->obj.vtable->klass;
5654 
5655 	g_assert (klass == dest->obj.vtable->klass);
5656 
5657 	size = mono_array_length (src);
5658 	g_assert (size == mono_array_length (dest));
5659 	size *= mono_array_element_size (klass);
5660 
5661 	array_full_copy_unchecked_size (src, dest, klass, size);
5662 }
5663 
5664 static void
array_full_copy_unchecked_size(MonoArray * src,MonoArray * dest,MonoClass * klass,uintptr_t size)5665 array_full_copy_unchecked_size (MonoArray *src, MonoArray *dest, MonoClass *klass, uintptr_t size)
5666 {
5667 	if (mono_gc_is_moving ()) {
5668 		if (klass->element_class->valuetype) {
5669 			if (klass->element_class->has_references)
5670 				mono_value_copy_array (dest, 0, mono_array_addr_with_size_fast (src, 0, 0), mono_array_length (src));
5671 			else
5672 				mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5673 		} else {
5674 			mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
5675 		}
5676 	} else {
5677 		mono_gc_memmove_atomic (&dest->vector, &src->vector, size);
5678 	}
5679 }
5680 
5681 /**
5682  * mono_array_clone_in_domain:
5683  * \param domain the domain in which the array will be cloned into
5684  * \param array the array to clone
5685  * \param error set on error
5686  * This routine returns a copy of the array that is hosted on the
5687  * specified \c MonoDomain.  On failure returns NULL and sets \p error.
5688  */
5689 MonoArrayHandle
mono_array_clone_in_domain(MonoDomain * domain,MonoArrayHandle array_handle,MonoError * error)5690 mono_array_clone_in_domain (MonoDomain *domain, MonoArrayHandle array_handle, MonoError *error)
5691 {
5692 	MONO_REQ_GC_UNSAFE_MODE;
5693 
5694 	MonoArrayHandle result = MONO_HANDLE_NEW (MonoArray, NULL);
5695 	uintptr_t size = 0;
5696 	MonoClass *klass = mono_handle_class (array_handle);
5697 
5698 	error_init (error);
5699 
5700 	/* Pin source array here - if bounds is non-NULL, it's a pointer into the object data */
5701 	uint32_t src_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, array_handle), TRUE);
5702 
5703 	MonoArrayBounds *array_bounds = MONO_HANDLE_GETVAL (array_handle, bounds);
5704 	MonoArrayHandle o;
5705 	if (array_bounds == NULL) {
5706 		size = mono_array_handle_length (array_handle);
5707 		o = mono_array_new_full_handle (domain, klass, &size, NULL, error);
5708 		goto_if_nok (error, leave);
5709 		size *= mono_array_element_size (klass);
5710 	} else {
5711 		uintptr_t *sizes = (uintptr_t *)alloca (klass->rank * sizeof (uintptr_t));
5712 		intptr_t *lower_bounds = (intptr_t *)alloca (klass->rank * sizeof (intptr_t));
5713 		size = mono_array_element_size (klass);
5714 		for (int i = 0; i < klass->rank; ++i) {
5715 			sizes [i] = array_bounds [i].length;
5716 			size *= array_bounds [i].length;
5717 			lower_bounds [i] = array_bounds [i].lower_bound;
5718 		}
5719 		o = mono_array_new_full_handle (domain, klass, sizes, lower_bounds, error);
5720 		goto_if_nok (error, leave);
5721 	}
5722 
5723 	uint32_t dst_handle = mono_gchandle_from_handle (MONO_HANDLE_CAST (MonoObject, o), TRUE);
5724 	array_full_copy_unchecked_size (MONO_HANDLE_RAW (array_handle), MONO_HANDLE_RAW (o), klass, size);
5725 	mono_gchandle_free (dst_handle);
5726 
5727 	MONO_HANDLE_ASSIGN (result, o);
5728 
5729 leave:
5730 	mono_gchandle_free (src_handle);
5731 	return result;
5732 }
5733 
5734 /**
5735  * mono_array_clone:
5736  * \param array the array to clone
5737  * \returns A newly created array who is a shallow copy of \p array
5738  */
5739 MonoArray*
mono_array_clone(MonoArray * array)5740 mono_array_clone (MonoArray *array)
5741 {
5742 	MONO_REQ_GC_UNSAFE_MODE;
5743 
5744 	MonoError error;
5745 	MonoArray *result = mono_array_clone_checked (array, &error);
5746 	mono_error_cleanup (&error);
5747 	return result;
5748 }
5749 
5750 /**
5751  * mono_array_clone_checked:
5752  * \param array the array to clone
5753  * \param error set on error
5754  * \returns A newly created array who is a shallow copy of \p array.  On
5755  * failure returns NULL and sets \p error.
5756  */
5757 MonoArray*
mono_array_clone_checked(MonoArray * array_raw,MonoError * error)5758 mono_array_clone_checked (MonoArray *array_raw, MonoError *error)
5759 {
5760 	MONO_REQ_GC_UNSAFE_MODE;
5761 	HANDLE_FUNCTION_ENTER ();
5762 	/* FIXME: callers of mono_array_clone_checked should use handles */
5763 	error_init (error);
5764 	MONO_HANDLE_DCL (MonoArray, array);
5765 	MonoArrayHandle result = mono_array_clone_in_domain (MONO_HANDLE_DOMAIN (array), array, error);
5766 	HANDLE_FUNCTION_RETURN_OBJ (result);
5767 }
5768 
5769 /* helper macros to check for overflow when calculating the size of arrays */
5770 #ifdef MONO_BIG_ARRAYS
5771 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
5772 #define MYGUINT_MAX MYGUINT64_MAX
5773 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5774 	    (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
5775 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5776 	    (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) &&	\
5777 					 ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
5778 #else
5779 #define MYGUINT32_MAX 4294967295U
5780 #define MYGUINT_MAX MYGUINT32_MAX
5781 #define CHECK_ADD_OVERFLOW_UN(a,b) \
5782 	    (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
5783 #define CHECK_MUL_OVERFLOW_UN(a,b) \
5784 	    (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) &&			\
5785 					 ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
5786 #endif
5787 
5788 gboolean
mono_array_calc_byte_len(MonoClass * klass,uintptr_t len,uintptr_t * res)5789 mono_array_calc_byte_len (MonoClass *klass, uintptr_t len, uintptr_t *res)
5790 {
5791 	MONO_REQ_GC_NEUTRAL_MODE;
5792 
5793 	uintptr_t byte_len;
5794 
5795 	byte_len = mono_array_element_size (klass);
5796 	if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
5797 		return FALSE;
5798 	byte_len *= len;
5799 	if (CHECK_ADD_OVERFLOW_UN (byte_len, MONO_SIZEOF_MONO_ARRAY))
5800 		return FALSE;
5801 	byte_len += MONO_SIZEOF_MONO_ARRAY;
5802 
5803 	*res = byte_len;
5804 
5805 	return TRUE;
5806 }
5807 
5808 /**
5809  * mono_array_new_full:
5810  * \param domain domain where the object is created
5811  * \param array_class array class
5812  * \param lengths lengths for each dimension in the array
5813  * \param lower_bounds lower bounds for each dimension in the array (may be NULL)
5814  * This routine creates a new array object with the given dimensions,
5815  * lower bounds and type.
5816  */
5817 MonoArray*
mono_array_new_full(MonoDomain * domain,MonoClass * array_class,uintptr_t * lengths,intptr_t * lower_bounds)5818 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds)
5819 {
5820 	MonoError error;
5821 	MonoArray *array = mono_array_new_full_checked (domain, array_class, lengths, lower_bounds, &error);
5822 	mono_error_cleanup (&error);
5823 
5824 	return array;
5825 }
5826 
5827 MonoArray*
mono_array_new_full_checked(MonoDomain * domain,MonoClass * array_class,uintptr_t * lengths,intptr_t * lower_bounds,MonoError * error)5828 mono_array_new_full_checked (MonoDomain *domain, MonoClass *array_class, uintptr_t *lengths, intptr_t *lower_bounds, MonoError *error)
5829 {
5830 	MONO_REQ_GC_UNSAFE_MODE;
5831 
5832 	uintptr_t byte_len = 0, len, bounds_size;
5833 	MonoObject *o;
5834 	MonoArray *array;
5835 	MonoArrayBounds *bounds;
5836 	MonoVTable *vtable;
5837 	int i;
5838 
5839 	error_init (error);
5840 
5841 	if (!array_class->inited)
5842 		mono_class_init (array_class);
5843 
5844 	len = 1;
5845 
5846 	/* A single dimensional array with a 0 lower bound is the same as an szarray */
5847 	if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
5848 		len = lengths [0];
5849 		if (len > MONO_ARRAY_MAX_INDEX) {
5850 			mono_error_set_generic_error (error, "System", "OverflowException", "");
5851 			return NULL;
5852 		}
5853 		bounds_size = 0;
5854 	} else {
5855 		bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
5856 
5857 		for (i = 0; i < array_class->rank; ++i) {
5858 			if (lengths [i] > MONO_ARRAY_MAX_INDEX) {
5859 				mono_error_set_generic_error (error, "System", "OverflowException", "");
5860 				return NULL;
5861 			}
5862 			if (CHECK_MUL_OVERFLOW_UN (len, lengths [i])) {
5863 				mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5864 				return NULL;
5865 			}
5866 			len *= lengths [i];
5867 		}
5868 	}
5869 
5870 	if (!mono_array_calc_byte_len (array_class, len, &byte_len)) {
5871 		mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5872 		return NULL;
5873 	}
5874 
5875 	if (bounds_size) {
5876 		/* align */
5877 		if (CHECK_ADD_OVERFLOW_UN (byte_len, 3)) {
5878 			mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5879 			return NULL;
5880 		}
5881 		byte_len = (byte_len + 3) & ~3;
5882 		if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size)) {
5883 			mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
5884 			return NULL;
5885 		}
5886 		byte_len += bounds_size;
5887 	}
5888 	/*
5889 	 * Following three lines almost taken from mono_object_new ():
5890 	 * they need to be kept in sync.
5891 	 */
5892 	vtable = mono_class_vtable_full (domain, array_class, error);
5893 	return_val_if_nok (error, NULL);
5894 
5895 	if (bounds_size)
5896 		o = (MonoObject *)mono_gc_alloc_array (vtable, byte_len, len, bounds_size);
5897 	else
5898 		o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, len);
5899 
5900 	if (G_UNLIKELY (!o)) {
5901 		mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
5902 		return NULL;
5903 	}
5904 
5905 	array = (MonoArray*)o;
5906 
5907 	bounds = array->bounds;
5908 
5909 	if (bounds_size) {
5910 		for (i = 0; i < array_class->rank; ++i) {
5911 			bounds [i].length = lengths [i];
5912 			if (lower_bounds)
5913 				bounds [i].lower_bound = lower_bounds [i];
5914 		}
5915 	}
5916 
5917 	return array;
5918 }
5919 
5920 /**
5921  * mono_array_new:
5922  * \param domain domain where the object is created
5923  * \param eclass element class
5924  * \param n number of array elements
5925  * This routine creates a new szarray with \p n elements of type \p eclass.
5926  */
5927 MonoArray *
mono_array_new(MonoDomain * domain,MonoClass * eclass,uintptr_t n)5928 mono_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5929 {
5930 	MONO_REQ_GC_UNSAFE_MODE;
5931 
5932 	MonoError error;
5933 	MonoArray *result = mono_array_new_checked (domain, eclass, n, &error);
5934 	mono_error_cleanup (&error);
5935 	return result;
5936 }
5937 
5938 /**
5939  * mono_array_new_checked:
5940  * \param domain domain where the object is created
5941  * \param eclass element class
5942  * \param n number of array elements
5943  * \param error set on error
5944  * This routine creates a new szarray with \p n elements of type \p eclass.
5945  * On failure returns NULL and sets \p error.
5946  */
5947 MonoArray *
mono_array_new_checked(MonoDomain * domain,MonoClass * eclass,uintptr_t n,MonoError * error)5948 mono_array_new_checked (MonoDomain *domain, MonoClass *eclass, uintptr_t n, MonoError *error)
5949 {
5950 	MonoClass *ac;
5951 
5952 	error_init (error);
5953 
5954 	ac = mono_array_class_get (eclass, 1);
5955 	g_assert (ac);
5956 
5957 	MonoVTable *vtable = mono_class_vtable_full (domain, ac, error);
5958 	return_val_if_nok (error, NULL);
5959 
5960 	return mono_array_new_specific_checked (vtable, n, error);
5961 }
5962 
5963 MonoArray*
ves_icall_array_new(MonoDomain * domain,MonoClass * eclass,uintptr_t n)5964 ves_icall_array_new (MonoDomain *domain, MonoClass *eclass, uintptr_t n)
5965 {
5966 	MonoError error;
5967 	MonoArray *arr = mono_array_new_checked (domain, eclass, n, &error);
5968 	mono_error_set_pending_exception (&error);
5969 
5970 	return arr;
5971 }
5972 
5973 /**
5974  * mono_array_new_specific:
5975  * \param vtable a vtable in the appropriate domain for an initialized class
5976  * \param n number of array elements
5977  * This routine is a fast alternative to \c mono_array_new for code which
5978  * can be sure about the domain it operates in.
5979  */
5980 MonoArray *
mono_array_new_specific(MonoVTable * vtable,uintptr_t n)5981 mono_array_new_specific (MonoVTable *vtable, uintptr_t n)
5982 {
5983 	MonoError error;
5984 	MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
5985 	mono_error_cleanup (&error);
5986 
5987 	return arr;
5988 }
5989 
5990 MonoArray*
mono_array_new_specific_checked(MonoVTable * vtable,uintptr_t n,MonoError * error)5991 mono_array_new_specific_checked (MonoVTable *vtable, uintptr_t n, MonoError *error)
5992 {
5993 	MONO_REQ_GC_UNSAFE_MODE;
5994 
5995 	MonoObject *o;
5996 	uintptr_t byte_len;
5997 
5998 	error_init (error);
5999 
6000 	if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
6001 		mono_error_set_generic_error (error, "System", "OverflowException", "");
6002 		return NULL;
6003 	}
6004 
6005 	if (!mono_array_calc_byte_len (vtable->klass, n, &byte_len)) {
6006 		mono_error_set_out_of_memory (error, "Could not allocate %i bytes", MONO_ARRAY_MAX_SIZE);
6007 		return NULL;
6008 	}
6009 	o = (MonoObject *)mono_gc_alloc_vector (vtable, byte_len, n);
6010 
6011 	if (G_UNLIKELY (!o)) {
6012 		mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", (gsize) byte_len);
6013 		return NULL;
6014 	}
6015 
6016 	return (MonoArray*)o;
6017 }
6018 
6019 MonoArray*
ves_icall_array_new_specific(MonoVTable * vtable,uintptr_t n)6020 ves_icall_array_new_specific (MonoVTable *vtable, uintptr_t n)
6021 {
6022 	MonoError error;
6023 	MonoArray *arr = mono_array_new_specific_checked (vtable, n, &error);
6024 	mono_error_set_pending_exception (&error);
6025 
6026 	return arr;
6027 }
6028 
6029 /**
6030  * mono_string_empty_wrapper:
6031  *
6032  * Returns: The same empty string instance as the managed string.Empty
6033  */
6034 MonoString*
mono_string_empty_wrapper(void)6035 mono_string_empty_wrapper (void)
6036 {
6037 	MonoDomain *domain = mono_domain_get ();
6038 	return mono_string_empty (domain);
6039 }
6040 
6041 /**
6042  * mono_string_empty:
6043  *
6044  * Returns: The same empty string instance as the managed string.Empty
6045  */
6046 MonoString*
mono_string_empty(MonoDomain * domain)6047 mono_string_empty (MonoDomain *domain)
6048 {
6049 	g_assert (domain);
6050 	g_assert (domain->empty_string);
6051 	return domain->empty_string;
6052 }
6053 
6054 /**
6055  * mono_string_new_utf16:
6056  * \param text a pointer to an utf16 string
6057  * \param len the length of the string
6058  * \returns A newly created string object which contains \p text.
6059  */
6060 MonoString *
mono_string_new_utf16(MonoDomain * domain,const guint16 * text,gint32 len)6061 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
6062 {
6063 	MONO_REQ_GC_UNSAFE_MODE;
6064 
6065 	MonoError error;
6066 	MonoString *res = NULL;
6067 	res = mono_string_new_utf16_checked (domain, text, len, &error);
6068 	mono_error_cleanup (&error);
6069 
6070 	return res;
6071 }
6072 
6073 /**
6074  * mono_string_new_utf16_checked:
6075  * \param text a pointer to an utf16 string
6076  * \param len the length of the string
6077  * \param error written on error.
6078  * \returns A newly created string object which contains \p text.
6079  * On error, returns NULL and sets \p error.
6080  */
6081 MonoString *
mono_string_new_utf16_checked(MonoDomain * domain,const guint16 * text,gint32 len,MonoError * error)6082 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6083 {
6084 	MONO_REQ_GC_UNSAFE_MODE;
6085 
6086 	MonoString *s;
6087 
6088 	error_init (error);
6089 
6090 	s = mono_string_new_size_checked (domain, len, error);
6091 	if (s != NULL)
6092 		memcpy (mono_string_chars (s), text, len * 2);
6093 
6094 	return s;
6095 }
6096 
6097 /**
6098  * mono_string_new_utf16_handle:
6099  * \param text a pointer to an utf16 string
6100  * \param len the length of the string
6101  * \param error written on error.
6102  * \returns A newly created string object which contains \p text.
6103  * On error, returns NULL and sets \p error.
6104  */
6105 MonoStringHandle
mono_string_new_utf16_handle(MonoDomain * domain,const guint16 * text,gint32 len,MonoError * error)6106 mono_string_new_utf16_handle (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
6107 {
6108 	return MONO_HANDLE_NEW (MonoString, mono_string_new_utf16_checked (domain, text, len, error));
6109 }
6110 
6111 /**
6112  * mono_string_new_utf32_checked:
6113  * \param text a pointer to an utf32 string
6114  * \param len the length of the string
6115  * \param error set on failure.
6116  * \returns A newly created string object which contains \p text. On failure returns NULL and sets \p error.
6117  */
6118 static MonoString *
mono_string_new_utf32_checked(MonoDomain * domain,const mono_unichar4 * text,gint32 len,MonoError * error)6119 mono_string_new_utf32_checked (MonoDomain *domain, const mono_unichar4 *text, gint32 len, MonoError *error)
6120 {
6121 	MONO_REQ_GC_UNSAFE_MODE;
6122 
6123 	MonoString *s;
6124 	mono_unichar2 *utf16_output = NULL;
6125 	gint32 utf16_len = 0;
6126 	GError *gerror = NULL;
6127 	glong items_written;
6128 
6129 	error_init (error);
6130 	utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
6131 
6132 	if (gerror)
6133 		g_error_free (gerror);
6134 
6135 	while (utf16_output [utf16_len]) utf16_len++;
6136 
6137 	s = mono_string_new_size_checked (domain, utf16_len, error);
6138 	return_val_if_nok (error, NULL);
6139 
6140 	memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
6141 
6142 	g_free (utf16_output);
6143 
6144 	return s;
6145 }
6146 
6147 /**
6148  * mono_string_new_utf32:
6149  * \param text a pointer to a UTF-32 string
6150  * \param len the length of the string
6151  * \returns A newly created string object which contains \p text.
6152  */
6153 MonoString *
mono_string_new_utf32(MonoDomain * domain,const mono_unichar4 * text,gint32 len)6154 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
6155 {
6156 	MonoError error;
6157 	MonoString *result = mono_string_new_utf32_checked (domain, text, len, &error);
6158 	mono_error_cleanup (&error);
6159 	return result;
6160 }
6161 
6162 /**
6163  * mono_string_new_size:
6164  * \param text a pointer to a UTF-16 string
6165  * \param len the length of the string
6166  * \returns A newly created string object of \p len
6167  */
6168 MonoString *
mono_string_new_size(MonoDomain * domain,gint32 len)6169 mono_string_new_size (MonoDomain *domain, gint32 len)
6170 {
6171 	MonoError error;
6172 	MonoString *str = mono_string_new_size_checked (domain, len, &error);
6173 	mono_error_cleanup (&error);
6174 
6175 	return str;
6176 }
6177 
6178 MonoString *
mono_string_new_size_checked(MonoDomain * domain,gint32 len,MonoError * error)6179 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
6180 {
6181 	MONO_REQ_GC_UNSAFE_MODE;
6182 
6183 	MonoString *s;
6184 	MonoVTable *vtable;
6185 	size_t size;
6186 
6187 	error_init (error);
6188 
6189 	/* check for overflow */
6190 	if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
6191 		mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
6192 		return NULL;
6193 	}
6194 
6195 	size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
6196 	g_assert (size > 0);
6197 
6198 	vtable = mono_class_vtable (domain, mono_defaults.string_class);
6199 	g_assert (vtable);
6200 
6201 	s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
6202 
6203 	if (G_UNLIKELY (!s)) {
6204 		mono_error_set_out_of_memory (error, "Could not allocate %zd bytes", size);
6205 		return NULL;
6206 	}
6207 
6208 	return s;
6209 }
6210 
6211 /**
6212  * mono_string_new_len:
6213  * \param text a pointer to an utf8 string
6214  * \param length number of bytes in \p text to consider
6215  * \returns A newly created string object which contains \p text.
6216  */
6217 MonoString*
mono_string_new_len(MonoDomain * domain,const char * text,guint length)6218 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
6219 {
6220 	MONO_REQ_GC_UNSAFE_MODE;
6221 
6222 	MonoError error;
6223 	MonoString *result = mono_string_new_len_checked (domain, text, length, &error);
6224 	mono_error_cleanup (&error);
6225 	return result;
6226 }
6227 
6228 /**
6229  * mono_string_new_len_checked:
6230  * \param text a pointer to an utf8 string
6231  * \param length number of bytes in \p text to consider
6232  * \param error set on error
6233  * \returns A newly created string object which contains \p text. On
6234  * failure returns NULL and sets \p error.
6235  */
6236 MonoString*
mono_string_new_len_checked(MonoDomain * domain,const char * text,guint length,MonoError * error)6237 mono_string_new_len_checked (MonoDomain *domain, const char *text, guint length, MonoError *error)
6238 {
6239 	MONO_REQ_GC_UNSAFE_MODE;
6240 
6241 	error_init (error);
6242 
6243 	GError *eg_error = NULL;
6244 	MonoString *o = NULL;
6245 	guint16 *ut = NULL;
6246 	glong items_written;
6247 
6248 	ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &eg_error);
6249 
6250 	if (!eg_error)
6251 		o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6252 	else
6253 		g_error_free (eg_error);
6254 
6255 	g_free (ut);
6256 
6257 	return o;
6258 }
6259 
6260 /**
6261  * mono_string_new:
6262  * \param text a pointer to a UTF-8 string
6263  * \deprecated Use \c mono_string_new_checked in new code.
6264  * This function asserts if it cannot allocate a new string.
6265  * \returns A newly created string object which contains \p text.
6266  */
6267 MonoString*
mono_string_new(MonoDomain * domain,const char * text)6268 mono_string_new (MonoDomain *domain, const char *text)
6269 {
6270 	MonoError error;
6271 	MonoString *res = NULL;
6272 	res = mono_string_new_checked (domain, text, &error);
6273 	mono_error_assert_ok (&error);
6274 	return res;
6275 }
6276 
6277 /**
6278  * mono_string_new_checked:
6279  * \param text a pointer to an utf8 string
6280  * \param merror set on error
6281  * \returns A newly created string object which contains \p text.
6282  * On error returns NULL and sets \p merror.
6283  */
6284 MonoString*
mono_string_new_checked(MonoDomain * domain,const char * text,MonoError * error)6285 mono_string_new_checked (MonoDomain *domain, const char *text, MonoError *error)
6286 {
6287 	MONO_REQ_GC_UNSAFE_MODE;
6288 
6289 	GError *eg_error = NULL;
6290 	MonoString *o = NULL;
6291 	guint16 *ut;
6292 	glong items_written;
6293 	int l;
6294 
6295 	error_init (error);
6296 
6297 	l = strlen (text);
6298 
6299 	ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &eg_error);
6300 
6301 	if (!eg_error) {
6302 		o = mono_string_new_utf16_checked (domain, ut, items_written, error);
6303 	} else {
6304 		mono_error_set_execution_engine (error, "String conversion error: %s", eg_error->message);
6305 	}
6306 
6307 	g_free (ut);
6308 
6309 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
6310 #if 0
6311 	gunichar2 *str;
6312 	const gchar *end;
6313 	int len;
6314 	MonoString *o = NULL;
6315 
6316 	if (!g_utf8_validate (text, -1, &end)) {
6317 		mono_error_set_argument (error, "text", "Not a valid utf8 string");
6318 		goto leave;
6319 	}
6320 
6321 	len = g_utf8_strlen (text, -1);
6322 	o = mono_string_new_size_checked (domain, len, error);
6323 	if (!o)
6324 		goto leave;
6325 	str = mono_string_chars (o);
6326 
6327 	while (text < end) {
6328 		*str++ = g_utf8_get_char (text);
6329 		text = g_utf8_next_char (text);
6330 	}
6331 
6332 leave:
6333 #endif
6334 	return o;
6335 }
6336 
6337 /**
6338  * mono_string_new_wrapper:
6339  * \param text pointer to UTF-8 characters.
6340  * Helper function to create a string object from \p text in the current domain.
6341  */
6342 MonoString*
mono_string_new_wrapper(const char * text)6343 mono_string_new_wrapper (const char *text)
6344 {
6345 	MONO_REQ_GC_UNSAFE_MODE;
6346 
6347 	MonoDomain *domain = mono_domain_get ();
6348 
6349 	if (text) {
6350 		MonoError error;
6351 		MonoString *result = mono_string_new_checked (domain, text, &error);
6352 		mono_error_assert_ok (&error);
6353 		return result;
6354 	}
6355 
6356 	return NULL;
6357 }
6358 
6359 /**
6360  * mono_value_box:
6361  * \param class the class of the value
6362  * \param value a pointer to the unboxed data
6363  * \returns A newly created object which contains \p value.
6364  */
6365 MonoObject *
mono_value_box(MonoDomain * domain,MonoClass * klass,gpointer value)6366 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
6367 {
6368 	MonoError error;
6369 	MonoObject *result = mono_value_box_checked (domain, klass, value, &error);
6370 	mono_error_cleanup (&error);
6371 	return result;
6372 }
6373 
6374 /**
6375  * mono_value_box_checked:
6376  * \param domain the domain of the new object
6377  * \param class the class of the value
6378  * \param value a pointer to the unboxed data
6379  * \param error set on error
6380  * \returns A newly created object which contains \p value. On failure
6381  * returns NULL and sets \p error.
6382  */
6383 MonoObject *
mono_value_box_checked(MonoDomain * domain,MonoClass * klass,gpointer value,MonoError * error)6384 mono_value_box_checked (MonoDomain *domain, MonoClass *klass, gpointer value, MonoError *error)
6385 {
6386 	MONO_REQ_GC_UNSAFE_MODE;
6387 	MonoObject *res;
6388 	int size;
6389 	MonoVTable *vtable;
6390 
6391 	error_init (error);
6392 
6393 	g_assert (klass->valuetype);
6394 	if (mono_class_is_nullable (klass))
6395 		return mono_nullable_box ((guint8 *)value, klass, error);
6396 
6397 	vtable = mono_class_vtable (domain, klass);
6398 	if (!vtable)
6399 		return NULL;
6400 	size = mono_class_instance_size (klass);
6401 	res = mono_object_new_alloc_specific_checked (vtable, error);
6402 	return_val_if_nok (error, NULL);
6403 
6404 	size = size - sizeof (MonoObject);
6405 
6406 	if (mono_gc_is_moving ()) {
6407 		g_assert (size == mono_class_value_size (klass, NULL));
6408 		mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
6409 	} else {
6410 #if NO_UNALIGNED_ACCESS
6411 		mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6412 #else
6413 		switch (size) {
6414 		case 1:
6415 			*((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
6416 			break;
6417 		case 2:
6418 			*(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
6419 			break;
6420 		case 4:
6421 			*(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
6422 			break;
6423 		case 8:
6424 			*(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
6425 			break;
6426 		default:
6427 			mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
6428 		}
6429 #endif
6430 	}
6431 	if (klass->has_finalize) {
6432 		mono_object_register_finalizer (res);
6433 		return_val_if_nok (error, NULL);
6434 	}
6435 	return res;
6436 }
6437 
6438 /**
6439  * mono_value_copy:
6440  * \param dest destination pointer
6441  * \param src source pointer
6442  * \param klass a valuetype class
6443  * Copy a valuetype from \p src to \p dest. This function must be used
6444  * when \p klass contains reference fields.
6445  */
6446 void
mono_value_copy(gpointer dest,gpointer src,MonoClass * klass)6447 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
6448 {
6449 	MONO_REQ_GC_UNSAFE_MODE;
6450 
6451 	mono_gc_wbarrier_value_copy (dest, src, 1, klass);
6452 }
6453 
6454 /**
6455  * mono_value_copy_array:
6456  * \param dest destination array
6457  * \param dest_idx index in the \p dest array
6458  * \param src source pointer
6459  * \param count number of items
6460  * Copy \p count valuetype items from \p src to the array \p dest at index \p dest_idx.
6461  * This function must be used when \p klass contains references fields.
6462  * Overlap is handled.
6463  */
6464 void
mono_value_copy_array(MonoArray * dest,int dest_idx,gpointer src,int count)6465 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
6466 {
6467 	MONO_REQ_GC_UNSAFE_MODE;
6468 
6469 	int size = mono_array_element_size (dest->obj.vtable->klass);
6470 	char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
6471 	g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
6472 	mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
6473 }
6474 
6475 /**
6476  * mono_object_get_domain:
6477  * \param obj object to query
6478  * \returns the \c MonoDomain where the object is hosted
6479  */
6480 MonoDomain*
mono_object_get_domain(MonoObject * obj)6481 mono_object_get_domain (MonoObject *obj)
6482 {
6483 	MONO_REQ_GC_UNSAFE_MODE;
6484 
6485 	return mono_object_domain (obj);
6486 }
6487 
6488 /**
6489  * mono_object_get_class:
6490  * \param obj object to query
6491  * Use this function to obtain the \c MonoClass* for a given \c MonoObject.
6492  * \returns the \c MonoClass of the object.
6493  */
6494 MonoClass*
mono_object_get_class(MonoObject * obj)6495 mono_object_get_class (MonoObject *obj)
6496 {
6497 	MONO_REQ_GC_UNSAFE_MODE;
6498 
6499 	return mono_object_class (obj);
6500 }
6501 /**
6502  * mono_object_get_size:
6503  * \param o object to query
6504  * \returns the size, in bytes, of \p o
6505  */
6506 guint
mono_object_get_size(MonoObject * o)6507 mono_object_get_size (MonoObject* o)
6508 {
6509 	MONO_REQ_GC_UNSAFE_MODE;
6510 
6511 	MonoClass* klass = mono_object_class (o);
6512 	if (klass == mono_defaults.string_class) {
6513 		return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
6514 	} else if (o->vtable->rank) {
6515 		MonoArray *array = (MonoArray*)o;
6516 		size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
6517 		if (array->bounds) {
6518 			size += 3;
6519 			size &= ~3;
6520 			size += sizeof (MonoArrayBounds) * o->vtable->rank;
6521 		}
6522 		return size;
6523 	} else {
6524 		return mono_class_instance_size (klass);
6525 	}
6526 }
6527 
6528 /**
6529  * mono_object_unbox:
6530  * \param obj object to unbox
6531  * \returns a pointer to the start of the valuetype boxed in this
6532  * object.
6533  *
6534  * This method will assert if the object passed is not a valuetype.
6535  */
6536 gpointer
mono_object_unbox(MonoObject * obj)6537 mono_object_unbox (MonoObject *obj)
6538 {
6539 	MONO_REQ_GC_UNSAFE_MODE;
6540 
6541 	/* add assert for valuetypes? */
6542 	g_assert (obj->vtable->klass->valuetype);
6543 	return ((char*)obj) + sizeof (MonoObject);
6544 }
6545 
6546 /**
6547  * mono_object_isinst:
6548  * \param obj an object
6549  * \param klass a pointer to a class
6550  * \returns \p obj if \p obj is derived from \p klass or NULL otherwise.
6551  */
6552 MonoObject *
mono_object_isinst(MonoObject * obj_raw,MonoClass * klass)6553 mono_object_isinst (MonoObject *obj_raw, MonoClass *klass)
6554 {
6555 	MONO_REQ_GC_UNSAFE_MODE;
6556 
6557 	HANDLE_FUNCTION_ENTER ();
6558 	MONO_HANDLE_DCL (MonoObject, obj);
6559 	MonoError error;
6560 	MonoObjectHandle result = mono_object_handle_isinst (obj, klass, &error);
6561 	mono_error_cleanup (&error);
6562 	HANDLE_FUNCTION_RETURN_OBJ (result);
6563 }
6564 
6565 
6566 /**
6567  * mono_object_isinst_checked:
6568  * \param obj an object
6569  * \param klass a pointer to a class
6570  * \param error set on error
6571  * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6572  * On failure returns NULL and sets \p error.
6573  */
6574 MonoObject *
mono_object_isinst_checked(MonoObject * obj_raw,MonoClass * klass,MonoError * error)6575 mono_object_isinst_checked (MonoObject *obj_raw, MonoClass *klass, MonoError *error)
6576 {
6577 	MONO_REQ_GC_UNSAFE_MODE;
6578 
6579 	HANDLE_FUNCTION_ENTER ();
6580 	error_init (error);
6581 	MONO_HANDLE_DCL (MonoObject, obj);
6582 	MonoObjectHandle result = mono_object_handle_isinst (obj, klass, error);
6583 	HANDLE_FUNCTION_RETURN_OBJ (result);
6584 }
6585 
6586 /**
6587  * mono_object_handle_isinst:
6588  * \param obj an object
6589  * \param klass a pointer to a class
6590  * \param error set on error
6591  * \returns \p obj if \p obj is derived from \p klass or NULL if it isn't.
6592  * On failure returns NULL and sets \p error.
6593  */
6594 MonoObjectHandle
mono_object_handle_isinst(MonoObjectHandle obj,MonoClass * klass,MonoError * error)6595 mono_object_handle_isinst (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6596 {
6597 	error_init (error);
6598 
6599 	if (!klass->inited)
6600 		mono_class_init (klass);
6601 
6602 	if (mono_class_is_marshalbyref (klass) || mono_class_is_interface (klass)) {
6603 		return mono_object_handle_isinst_mbyref (obj, klass, error);
6604 	}
6605 
6606 	MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6607 
6608 	if (!MONO_HANDLE_IS_NULL (obj) && mono_class_is_assignable_from (klass, mono_handle_class (obj)))
6609 		MONO_HANDLE_ASSIGN (result, obj);
6610 	return result;
6611 }
6612 
6613 /**
6614  * mono_object_isinst_mbyref:
6615  */
6616 MonoObject *
mono_object_isinst_mbyref(MonoObject * obj_raw,MonoClass * klass)6617 mono_object_isinst_mbyref (MonoObject *obj_raw, MonoClass *klass)
6618 {
6619 	MONO_REQ_GC_UNSAFE_MODE;
6620 
6621 	HANDLE_FUNCTION_ENTER ();
6622 	MonoError error;
6623 	MONO_HANDLE_DCL (MonoObject, obj);
6624 	MonoObjectHandle result = mono_object_handle_isinst_mbyref (obj, klass, &error);
6625 	mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
6626 	HANDLE_FUNCTION_RETURN_OBJ (result);
6627 }
6628 
6629 MonoObjectHandle
mono_object_handle_isinst_mbyref(MonoObjectHandle obj,MonoClass * klass,MonoError * error)6630 mono_object_handle_isinst_mbyref (MonoObjectHandle obj, MonoClass *klass, MonoError *error)
6631 {
6632 	error_init (error);
6633 
6634 	MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6635 
6636 	if (MONO_HANDLE_IS_NULL (obj))
6637 		goto leave;
6638 
6639 	MonoVTable *vt = MONO_HANDLE_GETVAL (obj, vtable);
6640 
6641 	if (mono_class_is_interface (klass)) {
6642 		if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
6643 			MONO_HANDLE_ASSIGN (result, obj);
6644 			goto leave;
6645 		}
6646 
6647 		/* casting an array one of the invariant interfaces that must act as such */
6648 		if (klass->is_array_special_interface) {
6649 			if (mono_class_is_assignable_from (klass, vt->klass)) {
6650 				MONO_HANDLE_ASSIGN (result, obj);
6651 				goto leave;
6652 			}
6653 		}
6654 
6655 		/*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
6656 		else if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, mono_handle_class (obj))) {
6657 			MONO_HANDLE_ASSIGN (result, obj);
6658 			goto leave;
6659 		}
6660 	} else {
6661 		MonoClass *oklass = vt->klass;
6662 		if (mono_class_is_transparent_proxy (oklass)){
6663 			MonoRemoteClass *remote_class = MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), remote_class);
6664 			oklass = remote_class->proxy_class;
6665 		}
6666 
6667 		mono_class_setup_supertypes (klass);
6668 		if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass)) {
6669 			MONO_HANDLE_ASSIGN (result, obj);
6670 			goto leave;
6671 		}
6672 	}
6673 #ifndef DISABLE_REMOTING
6674 	if (mono_class_is_transparent_proxy (vt->klass))
6675 	{
6676 		MonoBoolean custom_type_info =  MONO_HANDLE_GETVAL (MONO_HANDLE_CAST (MonoTransparentProxy, obj), custom_type_info);
6677 		if (!custom_type_info)
6678 			goto leave;
6679 		MonoDomain *domain = mono_domain_get ();
6680 		MonoObjectHandle rp = MONO_HANDLE_NEW (MonoObject, NULL);
6681 		MONO_HANDLE_GET (rp, MONO_HANDLE_CAST (MonoTransparentProxy, obj), rp);
6682 		MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
6683 		MonoMethod *im = NULL;
6684 		gpointer pa [2];
6685 
6686 		im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
6687 		if (!im) {
6688 			mono_error_set_not_supported (error, "Linked away.");
6689 			goto leave;
6690 		}
6691 		im = mono_object_handle_get_virtual_method (rp, im, error);
6692 		goto_if_nok (error, leave);
6693 		g_assert (im);
6694 
6695 		MonoReflectionTypeHandle reftype = mono_type_get_object_handle (domain, &klass->byval_arg, error);
6696 		goto_if_nok (error, leave);
6697 
6698 		pa [0] = MONO_HANDLE_RAW (reftype);
6699 		pa [1] = MONO_HANDLE_RAW (obj);
6700 		MonoObject *res = mono_runtime_invoke_checked (im, MONO_HANDLE_RAW (rp), pa, error);
6701 		goto_if_nok (error, leave);
6702 
6703 		if (*(MonoBoolean *) mono_object_unbox(res)) {
6704 			/* Update the vtable of the remote type, so it can safely cast to this new type */
6705 			mono_upgrade_remote_class (domain, obj, klass, error);
6706 			goto_if_nok (error, leave);
6707 			MONO_HANDLE_ASSIGN (result, obj);
6708 		}
6709 	}
6710 #endif /* DISABLE_REMOTING */
6711 leave:
6712 	return result;
6713 }
6714 
6715 /**
6716  * mono_object_castclass_mbyref:
6717  * \param obj an object
6718  * \param klass a pointer to a class
6719  * \returns \p obj if \p obj is derived from \p klass, returns NULL otherwise.
6720  */
6721 MonoObject *
mono_object_castclass_mbyref(MonoObject * obj_raw,MonoClass * klass)6722 mono_object_castclass_mbyref (MonoObject *obj_raw, MonoClass *klass)
6723 {
6724 	MONO_REQ_GC_UNSAFE_MODE;
6725 	HANDLE_FUNCTION_ENTER ();
6726 	MonoError error;
6727 	MONO_HANDLE_DCL (MonoObject, obj);
6728 	MonoObjectHandle result = MONO_HANDLE_NEW (MonoObject, NULL);
6729 	if (MONO_HANDLE_IS_NULL (obj))
6730 		goto leave;
6731 	MONO_HANDLE_ASSIGN (result, mono_object_handle_isinst_mbyref (obj, klass, &error));
6732 	mono_error_cleanup (&error);
6733 leave:
6734 	HANDLE_FUNCTION_RETURN_OBJ (result);
6735 }
6736 
6737 typedef struct {
6738 	MonoDomain *orig_domain;
6739 	MonoString *ins;
6740 	MonoString *res;
6741 } LDStrInfo;
6742 
6743 static void
str_lookup(MonoDomain * domain,gpointer user_data)6744 str_lookup (MonoDomain *domain, gpointer user_data)
6745 {
6746 	MONO_REQ_GC_UNSAFE_MODE;
6747 
6748 	LDStrInfo *info = (LDStrInfo *)user_data;
6749 	if (info->res || domain == info->orig_domain)
6750 		return;
6751 	info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
6752 }
6753 
6754 static MonoString*
mono_string_get_pinned(MonoString * str,MonoError * error)6755 mono_string_get_pinned (MonoString *str, MonoError *error)
6756 {
6757 	MONO_REQ_GC_UNSAFE_MODE;
6758 
6759 	error_init (error);
6760 
6761 	/* We only need to make a pinned version of a string if this is a moving GC */
6762 	if (!mono_gc_is_moving ())
6763 		return str;
6764 	int size;
6765 	MonoString *news;
6766 	size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
6767 	news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
6768 	if (news) {
6769 		memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
6770 		news->length = mono_string_length (str);
6771 	} else {
6772 		mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
6773 	}
6774 	return news;
6775 }
6776 
6777 static MonoString*
mono_string_is_interned_lookup(MonoString * str,int insert,MonoError * error)6778 mono_string_is_interned_lookup (MonoString *str, int insert, MonoError *error)
6779 {
6780 	MONO_REQ_GC_UNSAFE_MODE;
6781 
6782 	MonoGHashTable *ldstr_table;
6783 	MonoString *s, *res;
6784 	MonoDomain *domain;
6785 
6786 	error_init (error);
6787 
6788 	domain = ((MonoObject *)str)->vtable->domain;
6789 	ldstr_table = domain->ldstr_table;
6790 	ldstr_lock ();
6791 	res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6792 	if (res) {
6793 		ldstr_unlock ();
6794 		return res;
6795 	}
6796 	if (insert) {
6797 		/* Allocate outside the lock */
6798 		ldstr_unlock ();
6799 		s = mono_string_get_pinned (str, error);
6800 		return_val_if_nok (error, NULL);
6801 		if (s) {
6802 			ldstr_lock ();
6803 			res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
6804 			if (res) {
6805 				ldstr_unlock ();
6806 				return res;
6807 			}
6808 			mono_g_hash_table_insert (ldstr_table, s, s);
6809 			ldstr_unlock ();
6810 		}
6811 		return s;
6812 	} else {
6813 		LDStrInfo ldstr_info;
6814 		ldstr_info.orig_domain = domain;
6815 		ldstr_info.ins = str;
6816 		ldstr_info.res = NULL;
6817 
6818 		mono_domain_foreach (str_lookup, &ldstr_info);
6819 		if (ldstr_info.res) {
6820 			/*
6821 			 * the string was already interned in some other domain:
6822 			 * intern it in the current one as well.
6823 			 */
6824 			mono_g_hash_table_insert (ldstr_table, str, str);
6825 			ldstr_unlock ();
6826 			return str;
6827 		}
6828 	}
6829 	ldstr_unlock ();
6830 	return NULL;
6831 }
6832 
6833 /**
6834  * mono_string_is_interned:
6835  * \param o String to probe
6836  * \returns Whether the string has been interned.
6837  */
6838 MonoString*
mono_string_is_interned(MonoString * o)6839 mono_string_is_interned (MonoString *o)
6840 {
6841 	MonoError error;
6842 	MonoString *result = mono_string_is_interned_lookup (o, FALSE, &error);
6843 	/* This function does not fail. */
6844 	mono_error_assert_ok (&error);
6845 	return result;
6846 }
6847 
6848 /**
6849  * mono_string_intern:
6850  * \param o String to intern
6851  * Interns the string passed.
6852  * \returns The interned string.
6853  */
6854 MonoString*
mono_string_intern(MonoString * str)6855 mono_string_intern (MonoString *str)
6856 {
6857 	MonoError error;
6858 	MonoString *result = mono_string_intern_checked (str, &error);
6859 	mono_error_assert_ok (&error);
6860 	return result;
6861 }
6862 
6863 /**
6864  * mono_string_intern_checked:
6865  * \param o String to intern
6866  * \param error set on error.
6867  * Interns the string passed.
6868  * \returns The interned string.  On failure returns NULL and sets \p error
6869  */
6870 MonoString*
mono_string_intern_checked(MonoString * str,MonoError * error)6871 mono_string_intern_checked (MonoString *str, MonoError *error)
6872 {
6873 	MONO_REQ_GC_UNSAFE_MODE;
6874 
6875 	error_init (error);
6876 
6877 	return mono_string_is_interned_lookup (str, TRUE, error);
6878 }
6879 
6880 /**
6881  * mono_ldstr:
6882  * \param domain the domain where the string will be used.
6883  * \param image a metadata context
6884  * \param idx index into the user string table.
6885  * Implementation for the \c ldstr opcode.
6886  * \returns a loaded string from the \p image / \p idx combination.
6887  */
6888 MonoString*
mono_ldstr(MonoDomain * domain,MonoImage * image,guint32 idx)6889 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
6890 {
6891 	MonoError error;
6892 	MonoString *result = mono_ldstr_checked (domain, image, idx, &error);
6893 	mono_error_cleanup (&error);
6894 	return result;
6895 }
6896 
6897 /**
6898  * mono_ldstr_checked:
6899  * \param domain the domain where the string will be used.
6900  * \param image a metadata context
6901  * \param idx index into the user string table.
6902  * \param error set on error.
6903  * Implementation for the \c ldstr opcode.
6904  * \returns A loaded string from the \p image / \p idx combination.
6905  * On failure returns NULL and sets \p error.
6906  */
6907 MonoString*
mono_ldstr_checked(MonoDomain * domain,MonoImage * image,guint32 idx,MonoError * error)6908 mono_ldstr_checked (MonoDomain *domain, MonoImage *image, guint32 idx, MonoError *error)
6909 {
6910 	MONO_REQ_GC_UNSAFE_MODE;
6911 	error_init (error);
6912 
6913 	if (image->dynamic) {
6914 		MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL, error);
6915 		return str;
6916 	} else {
6917 		if (!mono_verifier_verify_string_signature (image, idx, NULL))
6918 			return NULL; /*FIXME we should probably be raising an exception here*/
6919 		MonoString *str = mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx), error);
6920 		return str;
6921 	}
6922 }
6923 
6924 /**
6925  * mono_ldstr_metadata_sig
6926  * \param domain the domain for the string
6927  * \param sig the signature of a metadata string
6928  * \param error set on error
6929  * \returns a \c MonoString for a string stored in the metadata. On
6930  * failure returns NULL and sets \p error.
6931  */
6932 static MonoString*
mono_ldstr_metadata_sig(MonoDomain * domain,const char * sig,MonoError * error)6933 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig, MonoError *error)
6934 {
6935 	MONO_REQ_GC_UNSAFE_MODE;
6936 
6937 	error_init (error);
6938 	const char *str = sig;
6939 	MonoString *o, *interned;
6940 	size_t len2;
6941 
6942 	len2 = mono_metadata_decode_blob_size (str, &str);
6943 	len2 >>= 1;
6944 
6945 	o = mono_string_new_utf16_checked (domain, (guint16*)str, len2, error);
6946 	return_val_if_nok (error, NULL);
6947 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
6948 	{
6949 		int i;
6950 		guint16 *p2 = (guint16*)mono_string_chars (o);
6951 		for (i = 0; i < len2; ++i) {
6952 			*p2 = GUINT16_FROM_LE (*p2);
6953 			++p2;
6954 		}
6955 	}
6956 #endif
6957 	ldstr_lock ();
6958 	interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6959 	ldstr_unlock ();
6960 	if (interned)
6961 		return interned; /* o will get garbage collected */
6962 
6963 	o = mono_string_get_pinned (o, error);
6964 	if (o) {
6965 		ldstr_lock ();
6966 		interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
6967 		if (!interned) {
6968 			mono_g_hash_table_insert (domain->ldstr_table, o, o);
6969 			interned = o;
6970 		}
6971 		ldstr_unlock ();
6972 	}
6973 
6974 	return interned;
6975 }
6976 
6977 /*
6978  * mono_ldstr_utf8:
6979  *
6980  *   Same as mono_ldstr, but return a NULL terminated utf8 string instead
6981  * of an object.
6982  */
6983 char*
mono_ldstr_utf8(MonoImage * image,guint32 idx,MonoError * error)6984 mono_ldstr_utf8 (MonoImage *image, guint32 idx, MonoError *error)
6985 {
6986 	const char *str;
6987 	size_t len2;
6988 	long written = 0;
6989 	char *as;
6990 	GError *gerror = NULL;
6991 
6992 	error_init (error);
6993 
6994 	if (!mono_verifier_verify_string_signature (image, idx, NULL))
6995 		return NULL; /*FIXME we should probably be raising an exception here*/
6996 	str = mono_metadata_user_string (image, idx);
6997 
6998 	len2 = mono_metadata_decode_blob_size (str, &str);
6999 	len2 >>= 1;
7000 
7001 	as = g_utf16_to_utf8 ((guint16*)str, len2, NULL, &written, &gerror);
7002 	if (gerror) {
7003 		mono_error_set_argument (error, "string", "%s", gerror->message);
7004 		g_error_free (gerror);
7005 		return NULL;
7006 	}
7007 	/* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7008 	if (len2 > written) {
7009 		/* allocate the total length and copy the part of the string that has been converted */
7010 		char *as2 = (char *)g_malloc0 (len2);
7011 		memcpy (as2, as, written);
7012 		g_free (as);
7013 		as = as2;
7014 	}
7015 
7016 	return as;
7017 }
7018 
7019 /**
7020  * mono_string_to_utf8:
7021  * \param s a \c System.String
7022  * \deprecated Use \c mono_string_to_utf8_checked to avoid having an exception arbitrarily raised.
7023  * \returns the UTF-8 representation for \p s.
7024  * The resulting buffer needs to be freed with \c mono_free().
7025  */
7026 char *
mono_string_to_utf8(MonoString * s)7027 mono_string_to_utf8 (MonoString *s)
7028 {
7029 	MONO_REQ_GC_UNSAFE_MODE;
7030 
7031 	MonoError error;
7032 	char *result = mono_string_to_utf8_checked (s, &error);
7033 
7034 	if (!is_ok (&error)) {
7035 		mono_error_cleanup (&error);
7036 		return NULL;
7037 	}
7038 	return result;
7039 }
7040 
7041 /**
7042  * mono_string_to_utf8_checked:
7043  * \param s a \c System.String
7044  * \param error a \c MonoError.
7045  * Converts a \c MonoString to its UTF-8 representation. May fail; check
7046  * \p error to determine whether the conversion was successful.
7047  * The resulting buffer should be freed with \c mono_free().
7048  */
7049 char *
mono_string_to_utf8_checked(MonoString * s,MonoError * error)7050 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
7051 {
7052 	MONO_REQ_GC_UNSAFE_MODE;
7053 
7054 	long written = 0;
7055 	char *as;
7056 	GError *gerror = NULL;
7057 
7058 	error_init (error);
7059 
7060 	if (s == NULL)
7061 		return NULL;
7062 
7063 	if (!s->length)
7064 		return g_strdup ("");
7065 
7066 	as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
7067 	if (gerror) {
7068 		mono_error_set_argument (error, "string", "%s", gerror->message);
7069 		g_error_free (gerror);
7070 		return NULL;
7071 	}
7072 	/* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7073 	if (s->length > written) {
7074 		/* allocate the total length and copy the part of the string that has been converted */
7075 		char *as2 = (char *)g_malloc0 (s->length);
7076 		memcpy (as2, as, written);
7077 		g_free (as);
7078 		as = as2;
7079 	}
7080 
7081 	return as;
7082 }
7083 
7084 char *
mono_string_handle_to_utf8(MonoStringHandle s,MonoError * error)7085 mono_string_handle_to_utf8 (MonoStringHandle s, MonoError *error)
7086 {
7087 	return mono_string_to_utf8_checked (MONO_HANDLE_RAW (s), error);
7088 }
7089 
7090 /**
7091  * mono_string_to_utf8_ignore:
7092  * \param s a MonoString
7093  * Converts a \c MonoString to its UTF-8 representation. Will ignore
7094  * invalid surrogate pairs.
7095  * The resulting buffer should be freed with \c mono_free().
7096  */
7097 char *
mono_string_to_utf8_ignore(MonoString * s)7098 mono_string_to_utf8_ignore (MonoString *s)
7099 {
7100 	MONO_REQ_GC_UNSAFE_MODE;
7101 
7102 	long written = 0;
7103 	char *as;
7104 
7105 	if (s == NULL)
7106 		return NULL;
7107 
7108 	if (!s->length)
7109 		return g_strdup ("");
7110 
7111 	as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
7112 
7113 	/* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
7114 	if (s->length > written) {
7115 		/* allocate the total length and copy the part of the string that has been converted */
7116 		char *as2 = (char *)g_malloc0 (s->length);
7117 		memcpy (as2, as, written);
7118 		g_free (as);
7119 		as = as2;
7120 	}
7121 
7122 	return as;
7123 }
7124 
7125 /**
7126  * mono_string_to_utf8_image_ignore:
7127  * \param s a \c System.String
7128  * Same as \c mono_string_to_utf8_ignore, but allocate the string from the image mempool.
7129  */
7130 char *
mono_string_to_utf8_image_ignore(MonoImage * image,MonoString * s)7131 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
7132 {
7133 	MONO_REQ_GC_UNSAFE_MODE;
7134 
7135 	return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
7136 }
7137 
7138 /**
7139  * mono_string_to_utf8_mp_ignore:
7140  * \param s a \c System.String
7141  * Same as \c mono_string_to_utf8_ignore, but allocate the string from a mempool.
7142  */
7143 char *
mono_string_to_utf8_mp_ignore(MonoMemPool * mp,MonoString * s)7144 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
7145 {
7146 	MONO_REQ_GC_UNSAFE_MODE;
7147 
7148 	return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
7149 }
7150 
7151 
7152 /**
7153  * mono_string_to_utf16:
7154  * \param s a \c MonoString
7155  * \returns a null-terminated array of the UTF-16 chars
7156  * contained in \p s. The result must be freed with \c g_free().
7157  * This is a temporary helper until our string implementation
7158  * is reworked to always include the null-terminating char.
7159  */
7160 mono_unichar2*
mono_string_to_utf16(MonoString * s)7161 mono_string_to_utf16 (MonoString *s)
7162 {
7163 	MONO_REQ_GC_UNSAFE_MODE;
7164 
7165 	char *as;
7166 
7167 	if (s == NULL)
7168 		return NULL;
7169 
7170 	as = (char *)g_malloc ((s->length * 2) + 2);
7171 	as [(s->length * 2)] = '\0';
7172 	as [(s->length * 2) + 1] = '\0';
7173 
7174 	if (!s->length) {
7175 		return (gunichar2 *)(as);
7176 	}
7177 
7178 	memcpy (as, mono_string_chars(s), s->length * 2);
7179 	return (gunichar2 *)(as);
7180 }
7181 
7182 /**
7183  * mono_string_to_utf32:
7184  * \param s a \c MonoString
7185  * \returns a null-terminated array of the UTF-32 (UCS-4) chars
7186  * contained in \p s. The result must be freed with \c g_free().
7187  */
7188 mono_unichar4*
mono_string_to_utf32(MonoString * s)7189 mono_string_to_utf32 (MonoString *s)
7190 {
7191 	MONO_REQ_GC_UNSAFE_MODE;
7192 
7193 	mono_unichar4 *utf32_output = NULL;
7194 	GError *error = NULL;
7195 	glong items_written;
7196 
7197 	if (s == NULL)
7198 		return NULL;
7199 
7200 	utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
7201 
7202 	if (error)
7203 		g_error_free (error);
7204 
7205 	return utf32_output;
7206 }
7207 
7208 /**
7209  * mono_string_from_utf16:
7210  * \param data the UTF-16 string (LPWSTR) to convert
7211  * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7212  * \returns a \c MonoString.
7213  */
7214 MonoString *
mono_string_from_utf16(gunichar2 * data)7215 mono_string_from_utf16 (gunichar2 *data)
7216 {
7217 	MonoError error;
7218 	MonoString *result = mono_string_from_utf16_checked (data, &error);
7219 	mono_error_cleanup (&error);
7220 	return result;
7221 }
7222 
7223 /**
7224  * mono_string_from_utf16_checked:
7225  * \param data the UTF-16 string (LPWSTR) to convert
7226  * \param error set on error
7227  * Converts a NULL-terminated UTF-16 string (LPWSTR) to a \c MonoString.
7228  * \returns a \c MonoString. On failure sets \p error and returns NULL.
7229  */
7230 MonoString *
mono_string_from_utf16_checked(gunichar2 * data,MonoError * error)7231 mono_string_from_utf16_checked (gunichar2 *data, MonoError *error)
7232 {
7233 
7234 	MONO_REQ_GC_UNSAFE_MODE;
7235 
7236 	error_init (error);
7237 	MonoDomain *domain = mono_domain_get ();
7238 	int len = 0;
7239 
7240 	if (!data)
7241 		return NULL;
7242 
7243 	while (data [len]) len++;
7244 
7245 	return mono_string_new_utf16_checked (domain, data, len, error);
7246 }
7247 
7248 /**
7249  * mono_string_from_utf32:
7250  * \param data the UTF-32 string (LPWSTR) to convert
7251  * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7252  * \returns a \c MonoString.
7253  */
7254 MonoString *
mono_string_from_utf32(mono_unichar4 * data)7255 mono_string_from_utf32 (mono_unichar4 *data)
7256 {
7257 	MonoError error;
7258 	MonoString *result = mono_string_from_utf32_checked (data, &error);
7259 	mono_error_cleanup (&error);
7260 	return result;
7261 }
7262 
7263 /**
7264  * mono_string_from_utf32_checked:
7265  * \param data the UTF-32 string (LPWSTR) to convert
7266  * \param error set on error
7267  * Converts a UTF-32 (UCS-4) string to a \c MonoString.
7268  * \returns a \c MonoString. On failure returns NULL and sets \p error.
7269  */
7270 MonoString *
mono_string_from_utf32_checked(mono_unichar4 * data,MonoError * error)7271 mono_string_from_utf32_checked (mono_unichar4 *data, MonoError *error)
7272 {
7273 	MONO_REQ_GC_UNSAFE_MODE;
7274 
7275 	error_init (error);
7276 	MonoString* result = NULL;
7277 	mono_unichar2 *utf16_output = NULL;
7278 	GError *gerror = NULL;
7279 	glong items_written;
7280 	int len = 0;
7281 
7282 	if (!data)
7283 		return NULL;
7284 
7285 	while (data [len]) len++;
7286 
7287 	utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &gerror);
7288 
7289 	if (gerror)
7290 		g_error_free (gerror);
7291 
7292 	result = mono_string_from_utf16_checked (utf16_output, error);
7293 	g_free (utf16_output);
7294 	return result;
7295 }
7296 
7297 static char *
mono_string_to_utf8_internal(MonoMemPool * mp,MonoImage * image,MonoString * s,gboolean ignore_error,MonoError * error)7298 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
7299 {
7300 	MONO_REQ_GC_UNSAFE_MODE;
7301 
7302 	char *r;
7303 	char *mp_s;
7304 	int len;
7305 
7306 	if (ignore_error) {
7307 		r = mono_string_to_utf8_ignore (s);
7308 	} else {
7309 		r = mono_string_to_utf8_checked (s, error);
7310 		if (!mono_error_ok (error))
7311 			return NULL;
7312 	}
7313 
7314 	if (!mp && !image)
7315 		return r;
7316 
7317 	len = strlen (r) + 1;
7318 	if (mp)
7319 		mp_s = (char *)mono_mempool_alloc (mp, len);
7320 	else
7321 		mp_s = (char *)mono_image_alloc (image, len);
7322 
7323 	memcpy (mp_s, r, len);
7324 
7325 	g_free (r);
7326 
7327 	return mp_s;
7328 }
7329 
7330 /**
7331  * mono_string_to_utf8_image:
7332  * \param s a \c System.String
7333  * Same as \c mono_string_to_utf8, but allocate the string from the image mempool.
7334  */
7335 char *
mono_string_to_utf8_image(MonoImage * image,MonoStringHandle s,MonoError * error)7336 mono_string_to_utf8_image (MonoImage *image, MonoStringHandle s, MonoError *error)
7337 {
7338 	MONO_REQ_GC_UNSAFE_MODE;
7339 
7340 	return mono_string_to_utf8_internal (NULL, image, MONO_HANDLE_RAW (s), FALSE, error); /* FIXME pin the string */
7341 }
7342 
7343 /**
7344  * mono_string_to_utf8_mp:
7345  * \param s a \c System.String
7346  * Same as \c mono_string_to_utf8, but allocate the string from a mempool.
7347  */
7348 char *
mono_string_to_utf8_mp(MonoMemPool * mp,MonoString * s,MonoError * error)7349 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
7350 {
7351 	MONO_REQ_GC_UNSAFE_MODE;
7352 
7353 	return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
7354 }
7355 
7356 
7357 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
7358 
7359 void
mono_install_eh_callbacks(MonoRuntimeExceptionHandlingCallbacks * cbs)7360 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
7361 {
7362 	eh_callbacks = *cbs;
7363 }
7364 
7365 MonoRuntimeExceptionHandlingCallbacks *
mono_get_eh_callbacks(void)7366 mono_get_eh_callbacks (void)
7367 {
7368 	return &eh_callbacks;
7369 }
7370 
7371 /**
7372  * mono_raise_exception:
7373  * \param ex exception object
7374  * Signal the runtime that the exception \p ex has been raised in unmanaged code.
7375  * DEPRECATED. DO NOT ADD NEW CALLERS FOR THIS FUNCTION.
7376  */
7377 void
mono_raise_exception(MonoException * ex)7378 mono_raise_exception (MonoException *ex)
7379 {
7380 	mono_raise_exception_deprecated (ex);
7381 }
7382 
7383 /*
7384  * DEPRECATED. DO NOT ADD NEW CALLERS FOR THIS FUNCTION.
7385  */
7386 void
mono_raise_exception_deprecated(MonoException * ex)7387 mono_raise_exception_deprecated (MonoException *ex)
7388 {
7389 	MONO_REQ_GC_UNSAFE_MODE;
7390 
7391 	eh_callbacks.mono_raise_exception (ex);
7392 }
7393 
7394 /**
7395  * mono_reraise_exception:
7396  * \param ex exception object
7397  * Signal the runtime that the exception \p ex has been raised in unmanaged code.
7398  * DEPRECATED. DO NOT ADD NEW CALLERS FOR THIS FUNCTION.
7399  */
7400 void
mono_reraise_exception(MonoException * ex)7401 mono_reraise_exception (MonoException *ex)
7402 {
7403 	mono_reraise_exception_deprecated (ex);
7404 }
7405 
7406 /*
7407  * DEPRECATED. DO NOT ADD NEW CALLERS FOR THIS FUNCTION.
7408  */
7409 void
mono_reraise_exception_deprecated(MonoException * ex)7410 mono_reraise_exception_deprecated (MonoException *ex)
7411 {
7412 	MONO_REQ_GC_UNSAFE_MODE;
7413 
7414 	eh_callbacks.mono_reraise_exception (ex);
7415 }
7416 
7417 /*
7418  * CTX must point to managed code.
7419  */
7420 void
mono_raise_exception_with_context(MonoException * ex,MonoContext * ctx)7421 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx)
7422 {
7423 	MONO_REQ_GC_UNSAFE_MODE;
7424 
7425 	eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
7426 }
7427 
7428 /**
7429  * mono_wait_handle_new:
7430  * \param domain Domain where the object will be created
7431  * \param handle Handle for the wait handle
7432  * \param error set on error.
7433  * \returns A new \c MonoWaitHandle created in the given domain for the
7434  * given handle.  On failure returns NULL and sets \p error.
7435  */
7436 MonoWaitHandle *
mono_wait_handle_new(MonoDomain * domain,HANDLE handle,MonoError * error)7437 mono_wait_handle_new (MonoDomain *domain, HANDLE handle, MonoError *error)
7438 {
7439 	MONO_REQ_GC_UNSAFE_MODE;
7440 
7441 	MonoWaitHandle *res;
7442 	gpointer params [1];
7443 	static MonoMethod *handle_set;
7444 
7445 	error_init (error);
7446 	res = (MonoWaitHandle *)mono_object_new_checked (domain, mono_defaults.manualresetevent_class, error);
7447 	return_val_if_nok (error, NULL);
7448 
7449 	/* Even though this method is virtual, it's safe to invoke directly, since the object type matches.  */
7450 	if (!handle_set)
7451 		handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
7452 
7453 	params [0] = &handle;
7454 
7455 	mono_runtime_invoke_checked (handle_set, res, params, error);
7456 	return res;
7457 }
7458 
7459 HANDLE
mono_wait_handle_get_handle(MonoWaitHandle * handle)7460 mono_wait_handle_get_handle (MonoWaitHandle *handle)
7461 {
7462 	MONO_REQ_GC_UNSAFE_MODE;
7463 
7464 	static MonoClassField *f_safe_handle = NULL;
7465 	MonoSafeHandle *sh;
7466 
7467 	if (!f_safe_handle) {
7468 		f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safeWaitHandle");
7469 		g_assert (f_safe_handle);
7470 	}
7471 
7472 	mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
7473 	return sh->handle;
7474 }
7475 
7476 
7477 static MonoObject*
mono_runtime_capture_context(MonoDomain * domain,MonoError * error)7478 mono_runtime_capture_context (MonoDomain *domain, MonoError *error)
7479 {
7480 #ifdef HOST_WASM
7481 	return mono_runtime_invoke_checked (mono_get_context_capture_method (), NULL, NULL, error);
7482 #else
7483 	MONO_REQ_GC_UNSAFE_MODE;
7484 
7485 	RuntimeInvokeFunction runtime_invoke;
7486 
7487 	error_init (error);
7488 
7489 	if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
7490 		MonoMethod *method = mono_get_context_capture_method ();
7491 		MonoMethod *wrapper;
7492 		if (!method)
7493 			return NULL;
7494 		wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
7495 		domain->capture_context_runtime_invoke = mono_compile_method_checked (wrapper, error);
7496 		return_val_if_nok (error, NULL);
7497 		domain->capture_context_method = mono_compile_method_checked (method, error);
7498 		return_val_if_nok (error, NULL);
7499 	}
7500 
7501 	runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
7502 
7503 	return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
7504 #endif
7505 }
7506 /**
7507  * mono_async_result_new:
7508  * \param domain domain where the object will be created.
7509  * \param handle wait handle.
7510  * \param state state to pass to AsyncResult
7511  * \param data C closure data.
7512  * \param error set on error.
7513  * Creates a new MonoAsyncResult (\c AsyncResult C# class) in the given domain.
7514  * If the handle is not null, the handle is initialized to a \c MonoWaitHandle.
7515  * On failure returns NULL and sets \p error.
7516  */
7517 MonoAsyncResult *
mono_async_result_new(MonoDomain * domain,HANDLE handle,MonoObject * state,gpointer data,MonoObject * object_data,MonoError * error)7518 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data, MonoError *error)
7519 {
7520 	MONO_REQ_GC_UNSAFE_MODE;
7521 
7522 	error_init (error);
7523 	MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new_checked (domain, mono_defaults.asyncresult_class, error);
7524 	return_val_if_nok (error, NULL);
7525 	MonoObject *context = mono_runtime_capture_context (domain, error);
7526 	return_val_if_nok (error, NULL);
7527 	/* we must capture the execution context from the original thread */
7528 	if (context) {
7529 		MONO_OBJECT_SETREF (res, execution_context, context);
7530 		/* note: result may be null if the flow is suppressed */
7531 	}
7532 
7533 	res->data = (void **)data;
7534 	MONO_OBJECT_SETREF (res, object_data, object_data);
7535 	MONO_OBJECT_SETREF (res, async_state, state);
7536 	MonoWaitHandle *wait_handle = mono_wait_handle_new (domain, handle, error);
7537 	return_val_if_nok (error, NULL);
7538 	if (handle != NULL)
7539 		MONO_OBJECT_SETREF (res, handle, (MonoObject *) wait_handle);
7540 
7541 	res->sync_completed = FALSE;
7542 	res->completed = FALSE;
7543 
7544 	return res;
7545 }
7546 
7547 MonoObject *
ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke(MonoAsyncResult * ares)7548 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
7549 {
7550 	MONO_REQ_GC_UNSAFE_MODE;
7551 
7552 	MonoError error;
7553 	MonoAsyncCall *ac;
7554 	MonoObject *res;
7555 
7556 	g_assert (ares);
7557 	g_assert (ares->async_delegate);
7558 
7559 	ac = (MonoAsyncCall*) ares->object_data;
7560 	if (!ac) {
7561 		res = mono_runtime_delegate_invoke_checked (ares->async_delegate, (void**) &ares->async_state, &error);
7562 		if (mono_error_set_pending_exception (&error))
7563 			return NULL;
7564 	} else {
7565 		gpointer wait_event = NULL;
7566 
7567 		ac->msg->exc = NULL;
7568 
7569 		res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args, &error);
7570 
7571 		/* The exit side of the invoke must not be aborted as it would leave the runtime in an undefined state */
7572 		mono_threads_begin_abort_protected_block ();
7573 
7574 		if (!ac->msg->exc) {
7575 			MonoException *ex = mono_error_convert_to_exception (&error);
7576 			ac->msg->exc = (MonoObject *)ex;
7577 		} else {
7578 			mono_error_cleanup (&error);
7579 		}
7580 
7581 		MONO_OBJECT_SETREF (ac, res, res);
7582 
7583 		mono_monitor_enter ((MonoObject*) ares);
7584 		ares->completed = 1;
7585 		if (ares->handle)
7586 			wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
7587 		mono_monitor_exit ((MonoObject*) ares);
7588 
7589 		if (wait_event != NULL)
7590 			mono_w32event_set (wait_event);
7591 
7592 		error_init (&error); //the else branch would leave it in an undefined state
7593 		if (ac->cb_method)
7594 			mono_runtime_invoke_checked (ac->cb_method, ac->cb_target, (gpointer*) &ares, &error);
7595 
7596 		mono_threads_end_abort_protected_block ();
7597 
7598 		if (mono_error_set_pending_exception (&error))
7599 			return NULL;
7600 	}
7601 
7602 	return res;
7603 }
7604 
7605 gboolean
mono_message_init(MonoDomain * domain,MonoMethodMessage * this_obj,MonoReflectionMethod * method,MonoArray * out_args,MonoError * error)7606 mono_message_init (MonoDomain *domain,
7607 		   MonoMethodMessage *this_obj,
7608 		   MonoReflectionMethod *method,
7609 		   MonoArray *out_args,
7610 		   MonoError *error)
7611 {
7612 	MONO_REQ_GC_UNSAFE_MODE;
7613 
7614 	static MonoMethod *init_message_method = NULL;
7615 
7616 	if (!init_message_method) {
7617 		init_message_method = mono_class_get_method_from_name (mono_defaults.mono_method_message_class, "InitMessage", 2);
7618 		g_assert (init_message_method != NULL);
7619 	}
7620 
7621 	error_init (error);
7622 	/* FIXME set domain instead? */
7623 	g_assert (domain == mono_domain_get ());
7624 
7625 	gpointer args[2];
7626 
7627 	args[0] = method;
7628 	args[1] = out_args;
7629 
7630 	mono_runtime_invoke_checked (init_message_method, this_obj, args, error);
7631 	return is_ok (error);
7632 }
7633 
7634 #ifndef DISABLE_REMOTING
7635 /**
7636  * mono_remoting_invoke:
7637  * \param real_proxy pointer to a \c RealProxy object
7638  * \param msg The \c MonoMethodMessage to execute
7639  * \param exc used to store exceptions
7640  * \param out_args used to store output arguments
7641  * This is used to call \c RealProxy::Invoke(). \c RealProxy::Invoke() returns an
7642  * \c IMessage interface and it is not trivial to extract results from there. So
7643  * we call an helper method \c PrivateInvoke instead of calling
7644  * \c RealProxy::Invoke() directly.
7645  * \returns the result object.
7646  */
7647 MonoObject *
mono_remoting_invoke(MonoObject * real_proxy,MonoMethodMessage * msg,MonoObject ** exc,MonoArray ** out_args,MonoError * error)7648 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, MonoObject **exc, MonoArray **out_args, MonoError *error)
7649 {
7650 	MONO_REQ_GC_UNSAFE_MODE;
7651 
7652 	MonoObject *o;
7653 	MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
7654 	gpointer pa [4];
7655 
7656 	g_assert (exc);
7657 
7658 	error_init (error);
7659 
7660 	/*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
7661 
7662 	if (!im) {
7663 		im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
7664 		if (!im) {
7665 			mono_error_set_not_supported (error, "Linked away.");
7666 			return NULL;
7667 		}
7668 		real_proxy->vtable->domain->private_invoke_method = im;
7669 	}
7670 
7671 	pa [0] = real_proxy;
7672 	pa [1] = msg;
7673 	pa [2] = exc;
7674 	pa [3] = out_args;
7675 
7676 	o = mono_runtime_try_invoke (im, NULL, pa, exc, error);
7677 	return_val_if_nok (error, NULL);
7678 
7679 	return o;
7680 }
7681 #endif
7682 
7683 MonoObject *
mono_message_invoke(MonoObject * target,MonoMethodMessage * msg,MonoObject ** exc,MonoArray ** out_args,MonoError * error)7684 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
7685 		     MonoObject **exc, MonoArray **out_args, MonoError *error)
7686 {
7687 	MONO_REQ_GC_UNSAFE_MODE;
7688 
7689 	static MonoClass *object_array_klass;
7690 	error_init (error);
7691 
7692 	MonoDomain *domain;
7693 	MonoMethod *method;
7694 	MonoMethodSignature *sig;
7695 	MonoArray *arr;
7696 	int i, j, outarg_count = 0;
7697 
7698 #ifndef DISABLE_REMOTING
7699 	if (target && mono_object_is_transparent_proxy (target)) {
7700 		MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
7701 		if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7702 			target = tp->rp->unwrapped_server;
7703 		} else {
7704 			return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args, error);
7705 		}
7706 	}
7707 #endif
7708 
7709 	domain = mono_domain_get ();
7710 	method = msg->method->method;
7711 	sig = mono_method_signature (method);
7712 
7713 	for (i = 0; i < sig->param_count; i++) {
7714 		if (sig->params [i]->byref)
7715 			outarg_count++;
7716 	}
7717 
7718 	if (!object_array_klass) {
7719 		MonoClass *klass;
7720 
7721 		klass = mono_array_class_get (mono_defaults.object_class, 1);
7722 		g_assert (klass);
7723 
7724 		mono_memory_barrier ();
7725 		object_array_klass = klass;
7726 	}
7727 
7728 	arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, error);
7729 	return_val_if_nok (error, NULL);
7730 
7731 	mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
7732 	*exc = NULL;
7733 
7734 	MonoObject *ret = mono_runtime_try_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc, error);
7735 	return_val_if_nok (error, NULL);
7736 
7737 	for (i = 0, j = 0; i < sig->param_count; i++) {
7738 		if (sig->params [i]->byref) {
7739 			MonoObject* arg;
7740 			arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
7741 			mono_array_setref (*out_args, j, arg);
7742 			j++;
7743 		}
7744 	}
7745 
7746 	return ret;
7747 }
7748 
7749 /**
7750  * prepare_to_string_method:
7751  * @obj: The object
7752  * @target: Set to @obj or unboxed value if a valuetype
7753  *
7754  * Returns: the ToString override for @obj. If @obj is a valuetype, @target is unboxed otherwise it's @obj.
7755  */
7756 static MonoMethod *
prepare_to_string_method(MonoObject * obj,void ** target)7757 prepare_to_string_method (MonoObject *obj, void **target)
7758 {
7759 	MONO_REQ_GC_UNSAFE_MODE;
7760 
7761 	static MonoMethod *to_string = NULL;
7762 	MonoMethod *method;
7763 	g_assert (target);
7764 	g_assert (obj);
7765 
7766 	*target = obj;
7767 
7768 	if (!to_string)
7769 		to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
7770 
7771 	method = mono_object_get_virtual_method (obj, to_string);
7772 
7773 	// Unbox value type if needed
7774 	if (mono_class_is_valuetype (mono_method_get_class (method))) {
7775 		*target = mono_object_unbox (obj);
7776 	}
7777 	return method;
7778 }
7779 
7780 /**
7781  * mono_object_to_string:
7782  * \param obj The object
7783  * \param exc Any exception thrown by \c ToString. May be NULL.
7784  * \returns the result of calling \c ToString on an object.
7785  */
7786 MonoString *
mono_object_to_string(MonoObject * obj,MonoObject ** exc)7787 mono_object_to_string (MonoObject *obj, MonoObject **exc)
7788 {
7789 	MonoError error;
7790 	MonoString *s = NULL;
7791 	void *target;
7792 	MonoMethod *method = prepare_to_string_method (obj, &target);
7793 	if (exc) {
7794 		s = (MonoString *) mono_runtime_try_invoke (method, target, NULL, exc, &error);
7795 		if (*exc == NULL && !mono_error_ok (&error))
7796 			*exc = (MonoObject*) mono_error_convert_to_exception (&error);
7797 		else
7798 			mono_error_cleanup (&error);
7799 	} else {
7800 		s = (MonoString *) mono_runtime_invoke_checked (method, target, NULL, &error);
7801 		mono_error_raise_exception_deprecated (&error); /* OK to throw, external only without a good alternative */
7802 	}
7803 
7804 	return s;
7805 }
7806 
7807 /**
7808  * mono_object_to_string_checked:
7809  * \param obj The object
7810  * \param error Set on error.
7811  * \returns the result of calling \c ToString() on an object. If the
7812  * method cannot be invoked or if it raises an exception, sets \p error
7813  * and returns NULL.
7814  */
7815 MonoString *
mono_object_to_string_checked(MonoObject * obj,MonoError * error)7816 mono_object_to_string_checked (MonoObject *obj, MonoError *error)
7817 {
7818 	error_init (error);
7819 	void *target;
7820 	MonoMethod *method = prepare_to_string_method (obj, &target);
7821 	return (MonoString*) mono_runtime_invoke_checked (method, target, NULL, error);
7822 }
7823 
7824 /**
7825  * mono_object_try_to_string:
7826  * \param obj The object
7827  * \param exc Any exception thrown by \c ToString(). Must not be NULL.
7828  * \param error Set if method cannot be invoked.
7829  * \returns the result of calling \c ToString() on an object. If the
7830  * method cannot be invoked sets \p error, if it raises an exception sets \p exc,
7831  * and returns NULL.
7832  */
7833 MonoString *
mono_object_try_to_string(MonoObject * obj,MonoObject ** exc,MonoError * error)7834 mono_object_try_to_string (MonoObject *obj, MonoObject **exc, MonoError *error)
7835 {
7836 	g_assert (exc);
7837 	error_init (error);
7838 	void *target;
7839 	MonoMethod *method = prepare_to_string_method (obj, &target);
7840 	return (MonoString*) mono_runtime_try_invoke (method, target, NULL, exc, error);
7841 }
7842 
7843 
7844 
7845 static char *
get_native_backtrace(MonoException * exc_raw)7846 get_native_backtrace (MonoException *exc_raw)
7847 {
7848 	HANDLE_FUNCTION_ENTER ();
7849 	MONO_HANDLE_DCL(MonoException, exc);
7850 	char * trace = mono_exception_handle_get_native_backtrace (exc);
7851 	HANDLE_FUNCTION_RETURN_VAL (trace);
7852 }
7853 
7854 /**
7855  * mono_print_unhandled_exception:
7856  * \param exc The exception
7857  * Prints the unhandled exception.
7858  */
7859 void
mono_print_unhandled_exception(MonoObject * exc)7860 mono_print_unhandled_exception (MonoObject *exc)
7861 {
7862 	MONO_REQ_GC_UNSAFE_MODE;
7863 
7864 	MonoString * str;
7865 	char *message = (char*)"";
7866 	gboolean free_message = FALSE;
7867 	MonoError error;
7868 
7869 	if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
7870 		message = g_strdup ("OutOfMemoryException");
7871 		free_message = TRUE;
7872 	} else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
7873 		message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
7874 		free_message = TRUE;
7875 	} else {
7876 
7877 		if (((MonoException*)exc)->native_trace_ips) {
7878 			message = get_native_backtrace ((MonoException*)exc);
7879 			free_message = TRUE;
7880 		} else {
7881 			MonoObject *other_exc = NULL;
7882 			str = mono_object_try_to_string (exc, &other_exc, &error);
7883 			if (other_exc == NULL && !is_ok (&error))
7884 				other_exc = (MonoObject*)mono_error_convert_to_exception (&error);
7885 			else
7886 				mono_error_cleanup (&error);
7887 			if (other_exc) {
7888 				char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
7889 				char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
7890 
7891 				message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
7892 					original_backtrace, nested_backtrace);
7893 
7894 				g_free (original_backtrace);
7895 				g_free (nested_backtrace);
7896 				free_message = TRUE;
7897 			} else if (str) {
7898 				message = mono_string_to_utf8_checked (str, &error);
7899 				if (!mono_error_ok (&error)) {
7900 					mono_error_cleanup (&error);
7901 					message = (char *) "";
7902 				} else {
7903 					free_message = TRUE;
7904 				}
7905 			}
7906 		}
7907 	}
7908 
7909 	/*
7910 	 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
7911 	 *	   exc->vtable->klass->name, message);
7912 	 */
7913 	g_printerr ("\nUnhandled Exception:\n%s\n", message);
7914 
7915 	if (free_message)
7916 		g_free (message);
7917 }
7918 
7919 /**
7920  * mono_delegate_ctor_with_method:
7921  * \param this pointer to an uninitialized delegate object
7922  * \param target target object
7923  * \param addr pointer to native code
7924  * \param method method
7925  * \param error set on error.
7926  * Initialize a delegate and sets a specific method, not the one
7927  * associated with \p addr.  This is useful when sharing generic code.
7928  * In that case \p addr will most probably not be associated with the
7929  * correct instantiation of the method.
7930  * On failure returns FALSE and sets \p error.
7931  */
7932 gboolean
mono_delegate_ctor_with_method(MonoObjectHandle this_obj,MonoObjectHandle target,gpointer addr,MonoMethod * method,MonoError * error)7933 mono_delegate_ctor_with_method (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoMethod *method, MonoError *error)
7934 {
7935 	MONO_REQ_GC_UNSAFE_MODE;
7936 
7937 	error_init (error);
7938 	MonoDelegateHandle delegate = MONO_HANDLE_CAST (MonoDelegate, this_obj);
7939 
7940 	g_assert (!MONO_HANDLE_IS_NULL (this_obj));
7941 	g_assert (addr);
7942 
7943 	MonoClass *klass = mono_handle_class (this_obj);
7944 	g_assert (mono_class_has_parent (klass, mono_defaults.multicastdelegate_class));
7945 
7946 	if (method)
7947 		MONO_HANDLE_SETVAL (delegate, method, MonoMethod*, method);
7948 
7949 	UnlockedIncrement (&mono_stats.delegate_creations);
7950 
7951 #ifndef DISABLE_REMOTING
7952 	if (!MONO_HANDLE_IS_NULL (target) && mono_class_is_transparent_proxy (mono_handle_class (target))) {
7953 		if (callbacks.interp_get_remoting_invoke) {
7954 			MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, callbacks.interp_get_remoting_invoke (addr, error));
7955 		} else {
7956 			g_assert (method);
7957 			method = mono_marshal_get_remoting_invoke (method);
7958 			MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, mono_compile_method_checked (method, error));
7959 		}
7960 		return_val_if_nok (error, FALSE);
7961 		MONO_HANDLE_SET (delegate, target, target);
7962 	} else
7963 #endif
7964 	{
7965 		MONO_HANDLE_SETVAL (delegate, method_ptr, gpointer, addr);
7966 		MONO_HANDLE_SET (delegate, target, target);
7967 	}
7968 
7969 	MONO_HANDLE_SETVAL (delegate, invoke_impl, gpointer, callbacks.create_delegate_trampoline (MONO_HANDLE_DOMAIN (delegate), mono_handle_class (delegate)));
7970 	if (callbacks.init_delegate)
7971 		callbacks.init_delegate (MONO_HANDLE_RAW (delegate)); /* FIXME: update init_delegate callback to take a MonoDelegateHandle */
7972 	return TRUE;
7973 }
7974 
7975 /**
7976  * mono_delegate_ctor:
7977  * \param this pointer to an uninitialized delegate object
7978  * \param target target object
7979  * \param addr pointer to native code
7980  * \param error set on error.
7981  * This is used to initialize a delegate.
7982  * On failure returns FALSE and sets \p error.
7983  */
7984 gboolean
mono_delegate_ctor(MonoObjectHandle this_obj,MonoObjectHandle target,gpointer addr,MonoError * error)7985 mono_delegate_ctor (MonoObjectHandle this_obj, MonoObjectHandle target, gpointer addr, MonoError *error)
7986 {
7987 	MONO_REQ_GC_UNSAFE_MODE;
7988 
7989 	error_init (error);
7990 	MonoDomain *domain = mono_domain_get ();
7991 	MonoJitInfo *ji;
7992 	MonoMethod *method = NULL;
7993 
7994 	g_assert (addr);
7995 
7996 	ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
7997 	/* Shared code */
7998 	if (!ji && domain != mono_get_root_domain ())
7999 		ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
8000 	if (ji) {
8001 		method = mono_jit_info_get_method (ji);
8002 		g_assert (!mono_class_is_gtd (method->klass));
8003 	}
8004 
8005 	return mono_delegate_ctor_with_method (this_obj, target, addr, method, error);
8006 }
8007 
8008 /**
8009  * mono_method_call_message_new:
8010  * \param method method to encapsulate
8011  * \param params parameters to the method
8012  * \param invoke optional, delegate invoke.
8013  * \param cb async callback delegate.
8014  * \param state state passed to the async callback.
8015  * \param error set on error.
8016   * Translates arguments pointers into a \c MonoMethodMessage.
8017  * On failure returns NULL and sets \p error.
8018  */
8019 MonoMethodMessage *
mono_method_call_message_new(MonoMethod * method,gpointer * params,MonoMethod * invoke,MonoDelegate ** cb,MonoObject ** state,MonoError * error)8020 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
8021 			      MonoDelegate **cb, MonoObject **state, MonoError *error)
8022 {
8023 	MONO_REQ_GC_UNSAFE_MODE;
8024 
8025 	error_init (error);
8026 
8027 	MonoDomain *domain = mono_domain_get ();
8028 	MonoMethodSignature *sig = mono_method_signature (method);
8029 	MonoMethodMessage *msg;
8030 	int i, count;
8031 
8032 	msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8033 	return_val_if_nok  (error, NULL);
8034 
8035 	if (invoke) {
8036 		MonoReflectionMethod *rm = mono_method_get_object_checked (domain, invoke, NULL, error);
8037 		return_val_if_nok (error, NULL);
8038 		mono_message_init (domain, msg, rm, NULL, error);
8039 		return_val_if_nok (error, NULL);
8040 		count =  sig->param_count - 2;
8041 	} else {
8042 		MonoReflectionMethod *rm = mono_method_get_object_checked (domain, method, NULL, error);
8043 		return_val_if_nok (error, NULL);
8044 		mono_message_init (domain, msg, rm, NULL, error);
8045 		return_val_if_nok (error, NULL);
8046 		count =  sig->param_count;
8047 	}
8048 
8049 	for (i = 0; i < count; i++) {
8050 		gpointer vpos;
8051 		MonoClass *klass;
8052 		MonoObject *arg;
8053 
8054 		if (sig->params [i]->byref)
8055 			vpos = *((gpointer *)params [i]);
8056 		else
8057 			vpos = params [i];
8058 
8059 		klass = mono_class_from_mono_type (sig->params [i]);
8060 
8061 		if (klass->valuetype) {
8062 			arg = mono_value_box_checked (domain, klass, vpos, error);
8063 			return_val_if_nok (error, NULL);
8064 		} else
8065 			arg = *((MonoObject **)vpos);
8066 
8067 		mono_array_setref (msg->args, i, arg);
8068 	}
8069 
8070 	if (cb != NULL && state != NULL) {
8071 		*cb = *((MonoDelegate **)params [i]);
8072 		i++;
8073 		*state = *((MonoObject **)params [i]);
8074 	}
8075 
8076 	return msg;
8077 }
8078 
8079 /**
8080  * mono_method_return_message_restore:
8081  *
8082  * Restore results from message based processing back to arguments pointers
8083  */
8084 void
mono_method_return_message_restore(MonoMethod * method,gpointer * params,MonoArray * out_args,MonoError * error)8085 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args, MonoError *error)
8086 {
8087 	MONO_REQ_GC_UNSAFE_MODE;
8088 
8089 	error_init (error);
8090 
8091 	MonoMethodSignature *sig = mono_method_signature (method);
8092 	int i, j, type, size, out_len;
8093 
8094 	if (out_args == NULL)
8095 		return;
8096 	out_len = mono_array_length (out_args);
8097 	if (out_len == 0)
8098 		return;
8099 
8100 	for (i = 0, j = 0; i < sig->param_count; i++) {
8101 		MonoType *pt = sig->params [i];
8102 
8103 		if (pt->byref) {
8104 			char *arg;
8105 			if (j >= out_len) {
8106 				mono_error_set_execution_engine (error, "The proxy call returned an incorrect number of output arguments");
8107 				return;
8108 			}
8109 
8110 			arg = (char *)mono_array_get (out_args, gpointer, j);
8111 			type = pt->type;
8112 
8113 			g_assert (type != MONO_TYPE_VOID);
8114 
8115 			if (MONO_TYPE_IS_REFERENCE (pt)) {
8116 				mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
8117 			} else {
8118 				if (arg) {
8119 					MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
8120 					size = mono_class_value_size (klass, NULL);
8121 					if (klass->has_references)
8122 						mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
8123 					else
8124 						mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
8125 				} else {
8126 					size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
8127 					mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
8128 				}
8129 			}
8130 
8131 			j++;
8132 		}
8133 	}
8134 }
8135 
8136 #ifndef DISABLE_REMOTING
8137 
8138 /**
8139  * mono_load_remote_field:
8140  * \param this pointer to an object
8141  * \param klass klass of the object containing \p field
8142  * \param field the field to load
8143  * \param res a storage to store the result
8144  * This method is called by the runtime on attempts to load fields of
8145  * transparent proxy objects. \p this points to such TP, \p klass is the class of
8146  * the object containing \p field. \p res is a storage location which can be
8147  * used to store the result.
8148  * \returns an address pointing to the value of field.
8149  */
8150 gpointer
mono_load_remote_field(MonoObject * this_obj,MonoClass * klass,MonoClassField * field,gpointer * res)8151 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
8152 {
8153 	MonoError error;
8154 	gpointer result = mono_load_remote_field_checked (this_obj, klass, field, res, &error);
8155 	mono_error_cleanup (&error);
8156 	return result;
8157 }
8158 
8159 /**
8160  * mono_load_remote_field_checked:
8161  * \param this pointer to an object
8162  * \param klass klass of the object containing \p field
8163  * \param field the field to load
8164  * \param res a storage to store the result
8165  * \param error set on error
8166  * This method is called by the runtime on attempts to load fields of
8167  * transparent proxy objects. \p this points to such TP, \p klass is the class of
8168  * the object containing \p field. \p res is a storage location which can be
8169  * used to store the result.
8170  * \returns an address pointing to the value of field.  On failure returns NULL and sets \p error.
8171  */
8172 gpointer
mono_load_remote_field_checked(MonoObject * this_obj,MonoClass * klass,MonoClassField * field,gpointer * res,MonoError * error)8173 mono_load_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res, MonoError *error)
8174 {
8175 	MONO_REQ_GC_UNSAFE_MODE;
8176 
8177 	static MonoMethod *getter = NULL;
8178 
8179 	error_init (error);
8180 
8181 	MonoDomain *domain = mono_domain_get ();
8182 	MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
8183 	MonoClass *field_class;
8184 	MonoMethodMessage *msg;
8185 	MonoArray *out_args;
8186 	MonoObject *exc;
8187 	char* full_name;
8188 
8189 	g_assert (mono_object_is_transparent_proxy (this_obj));
8190 	g_assert (res != NULL);
8191 
8192 	if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
8193 		mono_field_get_value (tp->rp->unwrapped_server, field, res);
8194 		return res;
8195 	}
8196 
8197 	if (!getter) {
8198 		getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
8199 		if (!getter) {
8200 			mono_error_set_not_supported (error, "Linked away.");
8201 			return NULL;
8202 		}
8203 	}
8204 
8205 	field_class = mono_class_from_mono_type (field->type);
8206 
8207 	msg = (MonoMethodMessage *)mono_object_new_checked (domain, mono_defaults.mono_method_message_class, error);
8208 	return_val_if_nok (error, NULL);
8209 	out_args = mono_array_new_checked (domain, mono_defaults.object_class, 1, error);
8210 	return_val_if_nok (error, NULL);
8211 	MonoReflectionMethod *rm = mono_method_get_object_checked (domain, getter, NULL, error);
8212 	return_val_if_nok (error, NULL);
8213 	mono_message_init (domain, msg, rm, out_args, error);
8214 	return_val_if_nok (error, NULL);
8215 
8216 	full_name = mono_type_get_full_name (klass);
8217 	MonoString *full_name_str = mono_string_new_checked (domain, full_name, error);
8218 	g_free (full_name);
8219 	return_val_if_nok (error, NULL);
8220 	mono_array_setref (msg->args, 0, full_name_str);
8221 	MonoString *field_name = mono_string_new_checked (domain, mono_field_get_name (field), error);
8222 	return_val_if_nok (error, NULL);
8223 	mono_array_setref (msg->args, 1, field_name);
8224 
8225 	mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args, error);
8226 	return_val_if_nok (error, NULL);
8227 
8228 	if (exc) {
8229 		mono_error_set_exception_instance (error, (MonoException *)exc);
8230 		return NULL;
8231 	}
8232 
8233 	if (mono_array_length (out_args) == 0)
8234 		return NULL;
8235 
8236 	mono_gc_wbarrier_generic_store (res, mono_array_get (out_args, MonoObject *, 0));
8237 
8238 	if (field_class->valuetype) {
8239 		return ((char *)*res) + sizeof (MonoObject);
8240 	} else
8241 		return res;
8242 }
8243 
8244 /**
8245  * mono_load_remote_field_new:
8246  * \param this
8247  * \param klass
8248  * \param field
8249  * Missing documentation.
8250  */
8251 MonoObject *
mono_load_remote_field_new(MonoObject * this_obj,MonoClass * klass,MonoClassField * field)8252 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
8253 {
8254 	MonoError error;
8255 
8256 	MonoObject *result = mono_load_remote_field_new_checked (this_obj, klass, field, &error);
8257 	mono_error_cleanup (&error);
8258 	return result;
8259 }
8260 
8261 /**
8262  * mono_load_remote_field_new_checked:
8263  * \param this pointer to an object
8264  * \param klass klass of the object containing \p field
8265  * \param field the field to load
8266  * \param error set on error.
8267  * This method is called by the runtime on attempts to load fields of
8268  * transparent proxy objects. \p this points to such TP, \p klass is the class of
8269  * the object containing \p field.
8270  * \returns a freshly allocated object containing the value of the field.  On failure returns NULL and sets \p error.
8271  */
8272 MonoObject *
mono_load_remote_field_new_checked(MonoObject * this_obj,MonoClass * klass,MonoClassField * field,MonoError * error)8273 mono_load_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoError *error)
8274 {
8275 	MONO_REQ_GC_UNSAFE_MODE;
8276 
8277 	error_init (error);
8278 
8279 	static MonoMethod *tp_load = NULL;
8280 
8281 	g_assert (mono_object_is_transparent_proxy (this_obj));
8282 
8283 	if (!tp_load) {
8284 		tp_load = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "LoadRemoteFieldNew", -1);
8285 		if (!tp_load) {
8286 			mono_error_set_not_supported (error, "Linked away.");
8287 			return NULL;
8288 		}
8289 	}
8290 
8291 	/* MonoType *type = mono_class_get_type (klass); */
8292 
8293 	gpointer args[2];
8294 	args [0] = &klass;
8295 	args [1] = &field;
8296 
8297 	return mono_runtime_invoke_checked (tp_load, this_obj, args, error);
8298 }
8299 
8300 /**
8301  * mono_store_remote_field:
8302  * \param this_obj pointer to an object
8303  * \param klass klass of the object containing \p field
8304  * \param field the field to load
8305  * \param val the value/object to store
8306  * This method is called by the runtime on attempts to store fields of
8307  * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8308  * the object containing \p field. \p val is the new value to store in \p field.
8309  */
8310 void
mono_store_remote_field(MonoObject * this_obj,MonoClass * klass,MonoClassField * field,gpointer val)8311 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
8312 {
8313 	MonoError error;
8314 	(void) mono_store_remote_field_checked (this_obj, klass, field, val, &error);
8315 	mono_error_cleanup (&error);
8316 }
8317 
8318 /**
8319  * mono_store_remote_field_checked:
8320  * \param this_obj pointer to an object
8321  * \param klass klass of the object containing \p field
8322  * \param field the field to load
8323  * \param val the value/object to store
8324  * \param error set on error
8325  * This method is called by the runtime on attempts to store fields of
8326  * transparent proxy objects. \p this_obj points to such TP, \p klass is the class of
8327  * the object containing \p field. \p val is the new value to store in \p field.
8328  * \returns on success returns TRUE, on failure returns FALSE and sets \p error.
8329  */
8330 gboolean
mono_store_remote_field_checked(MonoObject * this_obj,MonoClass * klass,MonoClassField * field,gpointer val,MonoError * error)8331 mono_store_remote_field_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val, MonoError *error)
8332 {
8333 
8334 	MONO_REQ_GC_UNSAFE_MODE;
8335 
8336 	error_init (error);
8337 
8338 	MonoDomain *domain = mono_domain_get ();
8339 	MonoClass *field_class;
8340 	MonoObject *arg;
8341 
8342 	g_assert (mono_object_is_transparent_proxy (this_obj));
8343 
8344 	field_class = mono_class_from_mono_type (field->type);
8345 
8346 	if (field_class->valuetype) {
8347 		arg = mono_value_box_checked (domain, field_class, val, error);
8348 		return_val_if_nok (error, FALSE);
8349 	} else {
8350 		arg = *((MonoObject**)val);
8351 	}
8352 
8353 	return mono_store_remote_field_new_checked (this_obj, klass, field, arg, error);
8354 }
8355 
8356 /**
8357  * mono_store_remote_field_new:
8358  * \param this_obj
8359  * \param klass
8360  * \param field
8361  * \param arg
8362  * Missing documentation
8363  */
8364 void
mono_store_remote_field_new(MonoObject * this_obj,MonoClass * klass,MonoClassField * field,MonoObject * arg)8365 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
8366 {
8367 	MonoError error;
8368 	(void) mono_store_remote_field_new_checked (this_obj, klass, field, arg, &error);
8369 	mono_error_cleanup (&error);
8370 }
8371 
8372 /**
8373  * mono_store_remote_field_new_checked:
8374  * \param this_obj
8375  * \param klass
8376  * \param field
8377  * \param arg
8378  * \param error
8379  * Missing documentation
8380  */
8381 gboolean
mono_store_remote_field_new_checked(MonoObject * this_obj,MonoClass * klass,MonoClassField * field,MonoObject * arg,MonoError * error)8382 mono_store_remote_field_new_checked (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg, MonoError *error)
8383 {
8384 	MONO_REQ_GC_UNSAFE_MODE;
8385 
8386 	static MonoMethod *tp_store = NULL;
8387 
8388 	error_init (error);
8389 
8390 	g_assert (mono_object_is_transparent_proxy (this_obj));
8391 
8392 	if (!tp_store) {
8393 		tp_store = mono_class_get_method_from_name (mono_defaults.transparent_proxy_class, "StoreRemoteField", -1);
8394 		if (!tp_store) {
8395 			mono_error_set_not_supported (error, "Linked away.");
8396 			return FALSE;
8397 		}
8398 	}
8399 
8400 	gpointer args[3];
8401 	args [0] = &klass;
8402 	args [1] = &field;
8403 	args [2] = arg;
8404 
8405 	mono_runtime_invoke_checked (tp_store, this_obj, args, error);
8406 	return is_ok (error);
8407 }
8408 #endif
8409 
8410 /**
8411  * mono_create_ftnptr:
8412  *
8413  * Given a function address, create a function descriptor for it.
8414  * This is only needed on some platforms.
8415  */
8416 gpointer
mono_create_ftnptr(MonoDomain * domain,gpointer addr)8417 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
8418 {
8419 	return callbacks.create_ftnptr (domain, addr);
8420 }
8421 
8422 /*
8423  * mono_get_addr_from_ftnptr:
8424  *
8425  *   Given a pointer to a function descriptor, return the function address.
8426  * This is only needed on some platforms.
8427  */
8428 gpointer
mono_get_addr_from_ftnptr(gpointer descr)8429 mono_get_addr_from_ftnptr (gpointer descr)
8430 {
8431 	return callbacks.get_addr_from_ftnptr (descr);
8432 }
8433 
8434 /**
8435  * mono_string_chars:
8436  * \param s a \c MonoString
8437  * \returns a pointer to the UTF-16 characters stored in the \c MonoString
8438  */
8439 gunichar2 *
mono_string_chars(MonoString * s)8440 mono_string_chars (MonoString *s)
8441 {
8442 	// MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
8443 
8444 	return s->chars;
8445 }
8446 
8447 /**
8448  * mono_string_length:
8449  * \param s MonoString
8450  * \returns the length in characters of the string
8451  */
8452 int
mono_string_length(MonoString * s)8453 mono_string_length (MonoString *s)
8454 {
8455 	MONO_REQ_GC_UNSAFE_MODE;
8456 
8457 	return s->length;
8458 }
8459 
8460 /**
8461  * mono_string_handle_length:
8462  * \param s \c MonoString
8463  * \returns the length in characters of the string
8464  */
8465 int
mono_string_handle_length(MonoStringHandle s)8466 mono_string_handle_length (MonoStringHandle s)
8467 {
8468 	MONO_REQ_GC_UNSAFE_MODE;
8469 
8470 	return MONO_HANDLE_GETVAL (s, length);
8471 }
8472 
8473 
8474 /**
8475  * mono_array_length:
8476  * \param array a \c MonoArray*
8477  * \returns the total number of elements in the array. This works for
8478  * both vectors and multidimensional arrays.
8479  */
8480 uintptr_t
mono_array_length(MonoArray * array)8481 mono_array_length (MonoArray *array)
8482 {
8483 	MONO_REQ_GC_UNSAFE_MODE;
8484 
8485 	return array->max_length;
8486 }
8487 
8488 /**
8489  * mono_array_addr_with_size:
8490  * \param array a \c MonoArray*
8491  * \param size size of the array elements
8492  * \param idx index into the array
8493  * Use this function to obtain the address for the \p idx item on the
8494  * \p array containing elements of size \p size.
8495  *
8496  * This method performs no bounds checking or type checking.
8497  * \returns the address of the \p idx element in the array.
8498  */
8499 char*
mono_array_addr_with_size(MonoArray * array,int size,uintptr_t idx)8500 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
8501 {
8502 	MONO_REQ_GC_UNSAFE_MODE;
8503 
8504 	return ((char*)(array)->vector) + size * idx;
8505 }
8506 
8507 
8508 MonoArray *
mono_glist_to_array(GList * list,MonoClass * eclass,MonoError * error)8509 mono_glist_to_array (GList *list, MonoClass *eclass, MonoError *error)
8510 {
8511 	MonoDomain *domain = mono_domain_get ();
8512 	MonoArray *res;
8513 	int len, i;
8514 
8515 	error_init (error);
8516 	if (!list)
8517 		return NULL;
8518 
8519 	len = g_list_length (list);
8520 	res = mono_array_new_checked (domain, eclass, len, error);
8521 	return_val_if_nok (error, NULL);
8522 
8523 	for (i = 0; list; list = list->next, i++)
8524 		mono_array_set (res, gpointer, i, list->data);
8525 
8526 	return res;
8527 }
8528 
8529 #if NEVER_DEFINED
8530 /*
8531  * The following section is purely to declare prototypes and
8532  * document the API, as these C files are processed by our
8533  * tool
8534  */
8535 
8536 /**
8537  * mono_array_set:
8538  * \param array array to alter
8539  * \param element_type A C type name, this macro will use the sizeof(type) to determine the element size
8540  * \param index index into the array
8541  * \param value value to set
8542  * Value Type version: This sets the \p index's element of the \p array
8543  * with elements of size sizeof(type) to the provided \p value.
8544  *
8545  * This macro does not attempt to perform type checking or bounds checking.
8546  *
8547  * Use this to set value types in a \c MonoArray.
8548  */
mono_array_set(MonoArray * array,Type element_type,uintptr_t index,Value value)8549 void mono_array_set(MonoArray *array, Type element_type, uintptr_t index, Value value)
8550 {
8551 }
8552 
8553 /**
8554  * mono_array_setref:
8555  * \param array array to alter
8556  * \param index index into the array
8557  * \param value value to set
8558  * Reference Type version. This sets the \p index's element of the
8559  * \p array with elements of size sizeof(type) to the provided \p value.
8560  *
8561  * This macro does not attempt to perform type checking or bounds checking.
8562  *
8563  * Use this to reference types in a \c MonoArray.
8564  */
mono_array_setref(MonoArray * array,uintptr_t index,MonoObject * object)8565 void mono_array_setref(MonoArray *array, uintptr_t index, MonoObject *object)
8566 {
8567 }
8568 
8569 /**
8570  * mono_array_get:
8571  * \param array array on which to operate on
8572  * \param element_type C element type (example: \c MonoString*, \c int, \c MonoObject*)
8573  * \param index index into the array
8574  *
8575  * Use this macro to retrieve the \p index element of an \p array and
8576  * extract the value assuming that the elements of the array match
8577  * the provided type value.
8578  *
8579  * This method can be used with both arrays holding value types and
8580  * reference types.   For reference types, the \p type parameter should
8581  * be a \c MonoObject* or any subclass of it, like \c MonoString*.
8582  *
8583  * This macro does not attempt to perform type checking or bounds checking.
8584  *
8585  * \returns The element at the \p index position in the \p array.
8586  */
mono_array_get(MonoArray * array,Type element_type,uintptr_t index)8587 Type mono_array_get (MonoArray *array, Type element_type, uintptr_t index)
8588 {
8589 }
8590 #endif
8591 
8592