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