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