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