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