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