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