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