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