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