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