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