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