2005-06-17 Zoltan Varga <vargaz@freemail.hu>
[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/os/gc_wrapper.h>
36 #include <mono/utils/strenc.h>
37
38 #ifdef HAVE_BOEHM_GC
39 #define NEED_TO_ZERO_PTRFREE 1
40 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
41 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
42 #ifdef HAVE_GC_GCJ_MALLOC
43 #define CREATION_SPEEDUP 1
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 #define MAKE_STRING_DESCRIPTOR(bitmap,sz) GC_make_descriptor((GC_bitmap)(bitmap),(sz))
47 #define MAKE_DESCRIPTOR(bitmap,sz,objsize) GC_make_descriptor((GC_bitmap)(bitmap),(sz))
48 #else
49 #define GC_NO_DESCRIPTOR (NULL)
50 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
51 #define MAKE_STRING_DESCRIPTOR(bitmap,sz) NULL
52 #define MAKE_DESCRIPTOR(bitmap,sz,objsize) NULL
53 #endif
54 #else
55 #ifdef HAVE_SGEN_GC
56 #define GC_NO_DESCRIPTOR (NULL)
57 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
58 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
59 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
60 #define MAKE_STRING_DESCRIPTOR(bitmap,sz) mono_gc_make_descr_for_string ()
61 #define MAKE_DESCRIPTOR(bitmap,sz,objsize) mono_gc_make_descr_for_object ((bitmap), (sz), (objsize))
62 #else
63 #define NEED_TO_ZERO_PTRFREE 1
64 #define GC_NO_DESCRIPTOR (NULL)
65 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
66 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
67 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
68 #define MAKE_STRING_DESCRIPTOR(bitmap,sz) NULL
69 #define MAKE_DESCRIPTOR(bitmap,sz,objsize) NULL
70 #endif
71 #endif
72
73 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
74 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
75
76 static void
77 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
78
79 static MonoString*
80 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig);
81
82 void
83 mono_runtime_object_init (MonoObject *this)
84 {
85         MonoMethod *method = NULL;
86         MonoClass *klass = this->vtable->klass;
87
88         method = mono_class_get_method_from_name (klass, ".ctor", 0);
89         g_assert (method);
90
91         if (method->klass->valuetype)
92                 this = mono_object_unbox (this);
93         mono_runtime_invoke (method, this, NULL, NULL);
94 }
95
96 /* The pseudo algorithm for type initialization from the spec
97 Note it doesn't say anything about domains - only threads.
98
99 2. If the type is initialized you are done.
100 2.1. If the type is not yet initialized, try to take an 
101      initialization lock.  
102 2.2. If successful, record this thread as responsible for 
103      initializing the type and proceed to step 2.3.
104 2.2.1. If not, see whether this thread or any thread 
105      waiting for this thread to complete already holds the lock.
106 2.2.2. If so, return since blocking would create a deadlock.  This thread 
107      will now see an incompletely initialized state for the type, 
108      but no deadlock will arise.
109 2.2.3  If not, block until the type is initialized then return.
110 2.3 Initialize the parent type and then all interfaces implemented 
111     by this type.
112 2.4 Execute the type initialization code for this type.
113 2.5 Mark the type as initialized, release the initialization lock, 
114     awaken any threads waiting for this type to be initialized, 
115     and return.
116
117 */
118
119 typedef struct
120 {
121         guint32 initializing_tid;
122         guint32 waiting_count;
123         gboolean done;
124         CRITICAL_SECTION initialization_section;
125 } TypeInitializationLock;
126
127 /* for locking access to type_initialization_hash and blocked_thread_hash */
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 }
167
168 /*
169  * mono_runtime_class_init:
170  * @vtable: vtable that needs to be initialized
171  *
172  * This routine calls the class constructor for @vtable.
173  */
174 void
175 mono_runtime_class_init (MonoVTable *vtable)
176 {
177         MonoException *exc;
178         MonoException *exc_to_throw;
179         MonoMethod *method = NULL;
180         MonoClass *klass;
181         gchar *full_name;
182
183         MONO_ARCH_SAVE_REGS;
184
185         if (vtable->initialized)
186                 return;
187
188         exc = NULL;
189         klass = vtable->klass;
190
191         method = mono_class_get_cctor (klass);
192
193         if (method) {
194                 MonoDomain *domain = vtable->domain;
195                 TypeInitializationLock *lock;
196                 guint32 tid = GetCurrentThreadId();
197                 int do_initialization = 0;
198                 MonoDomain *last_domain = NULL;
199
200                 EnterCriticalSection (&type_initialization_section);
201                 /* double check... */
202                 if (vtable->initialized) {
203                         LeaveCriticalSection (&type_initialization_section);
204                         return;
205                 }
206                 lock = g_hash_table_lookup (type_initialization_hash, vtable);
207                 if (lock == NULL) {
208                         /* This thread will get to do the initialization */
209                         if (mono_domain_get () != domain) {
210                                 /* Transfer into the target domain */
211                                 last_domain = mono_domain_get ();
212                                 if (!mono_domain_set (domain, FALSE)) {
213                                         vtable->initialized = 1;
214                                         LeaveCriticalSection (&type_initialization_section);
215                                         mono_raise_exception (mono_get_exception_appdomain_unloaded ());
216                                 }
217                         }
218                         lock = g_malloc (sizeof(TypeInitializationLock));
219                         InitializeCriticalSection (&lock->initialization_section);
220                         lock->initializing_tid = tid;
221                         lock->waiting_count = 1;
222                         lock->done = FALSE;
223                         /* grab the vtable lock while this thread still owns type_initialization_section */
224                         EnterCriticalSection (&lock->initialization_section);
225                         g_hash_table_insert (type_initialization_hash, vtable, lock);
226                         do_initialization = 1;
227                 } else {
228                         gpointer blocked;
229                         TypeInitializationLock *pending_lock;
230
231                         if (lock->initializing_tid == tid || lock->done) {
232                                 LeaveCriticalSection (&type_initialization_section);
233                                 return;
234                         }
235                         /* see if the thread doing the initialization is already blocked on this thread */
236                         blocked = GUINT_TO_POINTER (lock->initializing_tid);
237                         while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
238                                 if (pending_lock->initializing_tid == tid) {
239                                         if (!pending_lock->done) {
240                                                 LeaveCriticalSection (&type_initialization_section);
241                                                 return;
242                                         } else {
243                                                 /* the thread doing the initialization is blocked on this thread,
244                                                    but on a lock that has already been freed. It just hasn't got
245                                                    time to awake */
246                                                 break;
247                                         }
248                                 }
249                                 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
250                         }
251                         ++lock->waiting_count;
252                         /* record the fact that we are waiting on the initializing thread */
253                         g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
254                 }
255                 LeaveCriticalSection (&type_initialization_section);
256
257                 if (do_initialization) {
258                         mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
259                         if (last_domain)
260                                 mono_domain_set (last_domain, TRUE);
261                         lock->done = TRUE;
262                         LeaveCriticalSection (&lock->initialization_section);
263                 } else {
264                         /* this just blocks until the initializing thread is done */
265                         EnterCriticalSection (&lock->initialization_section);
266                         LeaveCriticalSection (&lock->initialization_section);
267                 }
268
269                 EnterCriticalSection (&type_initialization_section);
270                 if (lock->initializing_tid != tid)
271                         g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
272                 --lock->waiting_count;
273                 if (lock->waiting_count == 0) {
274                         DeleteCriticalSection (&lock->initialization_section);
275                         g_hash_table_remove (type_initialization_hash, vtable);
276                         g_free (lock);
277                 }
278                 vtable->initialized = 1;
279                 /* FIXME: if the cctor fails, the type must be marked as unusable */
280                 LeaveCriticalSection (&type_initialization_section);
281         } else {
282                 vtable->initialized = 1;
283                 return;
284         }
285
286         if (exc == NULL ||
287             (klass->image == mono_defaults.corlib &&            
288              !strcmp (klass->name_space, "System") &&
289              !strcmp (klass->name, "TypeInitializationException")))
290                 return; /* No static constructor found or avoid infinite loop */
291
292         if (klass->name_space && *klass->name_space)
293                 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
294         else
295                 full_name = g_strdup (klass->name);
296
297         exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
298         g_free (full_name);
299
300         mono_raise_exception (exc_to_throw);
301 }
302
303 static
304 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
305 {
306         TypeInitializationLock *lock = (TypeInitializationLock*) value;
307         if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
308                 lock->done = TRUE;
309                 LeaveCriticalSection (&lock->initialization_section);
310                 --lock->waiting_count;
311                 if (lock->waiting_count == 0) {
312                         DeleteCriticalSection (&lock->initialization_section);
313                         g_free (lock);
314                         return TRUE;
315                 }
316         }
317         return FALSE;
318 }
319
320 void
321 mono_release_type_locks (MonoThread *thread)
322 {
323         EnterCriticalSection (&type_initialization_section);
324         g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
325         LeaveCriticalSection (&type_initialization_section);
326 }
327
328 static gpointer
329 default_trampoline (MonoMethod *method)
330 {
331         return method;
332 }
333
334 static gpointer
335 default_remoting_trampoline (MonoMethod *method, MonoRemotingTarget target)
336 {
337         g_error ("remoting not installed");
338         return NULL;
339 }
340
341 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
342 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
343
344 void
345 mono_install_trampoline (MonoTrampoline func) 
346 {
347         arch_create_jit_trampoline = func? func: default_trampoline;
348 }
349
350 void
351 mono_install_remoting_trampoline (MonoRemotingTrampoline func) 
352 {
353         arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
354 }
355
356 static MonoCompileFunc default_mono_compile_method = NULL;
357
358 /**
359  * mono_install_compile_method:
360  * @func: function to install
361  *
362  * This is a VM internal routine
363  */
364 void        
365 mono_install_compile_method (MonoCompileFunc func)
366 {
367         default_mono_compile_method = func;
368 }
369
370 /**
371  * mono_compile_method:
372  * @method: The method to compile.
373  *
374  * This JIT-compiles the method, and returns the pointer to the native code
375  * produced.
376  */
377 gpointer 
378 mono_compile_method (MonoMethod *method)
379 {
380         if (!default_mono_compile_method) {
381                 g_error ("compile method called on uninitialized runtime");
382                 return NULL;
383         }
384         return default_mono_compile_method (method);
385 }
386
387 static MonoFreeMethodFunc default_mono_free_method = NULL;
388
389 /**
390  * mono_install_free_method:
391  * @func: pointer to the MonoFreeMethodFunc used to release a method
392  *
393  * This is an internal VM routine, it is used for the engines to
394  * register a handler to release the resources associated with a method.
395  *
396  * Methods are freed when no more references to the delegate that holds
397  * them are left.
398  */
399 void
400 mono_install_free_method (MonoFreeMethodFunc func)
401 {
402         default_mono_free_method = func;
403 }
404
405 /**
406  * mono_runtime_free_method:
407  * @domain; domain where the method is hosted
408  * @method: method to release
409  *
410  * This routine is invoked to free the resources associated with
411  * a method that has been JIT compiled.  This is used to discard
412  * methods that were used only temporarily (for example, used in marshalling)
413  *
414  */
415 void
416 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
417 {
418         if (default_mono_free_method != NULL)
419                 default_mono_free_method (domain, method);
420
421         mono_free_method (method);
422 }
423
424 static MonoInitVTableFunc init_vtable_func = NULL;
425
426 /**
427  * mono_install_init_vtable:
428  * @func: pointer to the function to be installed
429  *
430  *   Register a function which will be called by the runtime to initialize the
431  * method pointers inside a vtable. The JIT can use this function to load the
432  * vtable from the AOT file for example.
433  */
434 void
435 mono_install_init_vtable (MonoInitVTableFunc func)
436 {
437         init_vtable_func = func;
438 }
439
440 /*
441  * The vtables in the root appdomain are assumed to be reachable by other 
442  * roots, and we don't use typed allocation in the other domains.
443  */
444
445 /* The sync block is no longer a GC pointer */
446 #define GC_HEADER_BITMAP (0)
447
448 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
449
450 static gsize*
451 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set)
452 {
453         MonoClassField *field;
454         MonoClass *p;
455         guint32 pos;
456         int max_size = class->instance_size / sizeof (gpointer);
457         if (max_size > size) {
458                 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
459         }
460
461         for (p = class; p != NULL; p = p->parent) {
462                 gpointer iter = NULL;
463                 while ((field = mono_class_get_fields (p, &iter))) {
464                         MonoType *type;
465
466                         if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
467                                 continue;
468                         /* FIXME: should not happen, flag as type load error */
469                         if (field->type->byref)
470                                 break;
471
472                         pos = field->offset / sizeof (gpointer);
473                         pos += offset;
474
475                         type = mono_type_get_underlying_type (field->type);
476                         switch (type->type) {
477                         /* FIXME: _I and _U and _PTR should be removed eventually */
478                         case MONO_TYPE_I:
479                         case MONO_TYPE_U:
480                         case MONO_TYPE_PTR:
481                         case MONO_TYPE_FNPTR:
482                         case MONO_TYPE_STRING:
483                         case MONO_TYPE_SZARRAY:
484                         case MONO_TYPE_CLASS:
485                         case MONO_TYPE_OBJECT:
486                         case MONO_TYPE_ARRAY:
487                                 g_assert ((field->offset % sizeof(gpointer)) == 0);
488
489                                 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
490                                 *max_set = MAX (*max_set, pos);
491                                 break;
492                         case MONO_TYPE_VALUETYPE: {
493                                 MonoClass *fclass = field->type->data.klass;
494                                 if (fclass->has_references) {
495                                         /* remove the object header */
496                                         compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set);
497                                 }
498                                 break;
499                         }
500                         case MONO_TYPE_I1:
501                         case MONO_TYPE_U1:
502                         case MONO_TYPE_I2:
503                         case MONO_TYPE_U2:
504                         case MONO_TYPE_I4:
505                         case MONO_TYPE_U4:
506                         case MONO_TYPE_I8:
507                         case MONO_TYPE_U8:
508                         case MONO_TYPE_R4:
509                         case MONO_TYPE_R8:
510                         case MONO_TYPE_BOOLEAN:
511                         case MONO_TYPE_CHAR:
512                                 break;
513                         default:
514                                 g_assert_not_reached ();
515                                 break;
516                         }
517                 }
518         }
519         return bitmap;
520 }
521
522 static void
523 mono_class_compute_gc_descriptor (MonoClass *class)
524 {
525         int max_set = 0;
526         gsize *bitmap;
527         gsize default_bitmap [4] = {0};
528         static gboolean gcj_inited = FALSE;
529
530         if (!gcj_inited) {
531                 mono_loader_lock ();
532
533                 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
534                 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
535                 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
536
537 #ifdef HAVE_GC_GCJ_MALLOC
538
539                 GC_init_gcj_malloc (5, NULL);
540
541 #ifdef GC_REDIRECT_TO_LOCAL
542                 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
543                 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
544 #endif
545                 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
546                 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
547 #endif
548                 gcj_inited = TRUE;
549                 mono_loader_unlock ();
550         }
551
552         if (!class->inited)
553                 mono_class_init (class);
554
555         if (class->gc_descr_inited)
556                 return;
557
558         class->gc_descr_inited = TRUE;
559         class->gc_descr = GC_NO_DESCRIPTOR;
560
561         bitmap = default_bitmap;
562         if (class == mono_defaults.string_class) {
563                 class->gc_descr = (gpointer)MAKE_STRING_DESCRIPTOR (bitmap, 2);
564         } else if (class->rank) {
565                 mono_class_compute_gc_descriptor (class->element_class);
566 #ifdef HAVE_SGEN_GC
567                 /* libgc has no usable support for arrays... */
568                 if (!class->element_class->valuetype) {
569                         gsize abm = 1;
570                         class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
571                         /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
572                                 class->name_space, class->name);*/
573                 } else {
574                         /* remove the object header */
575                         bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (sizeof (MonoObject) / sizeof (gpointer)), &max_set);
576                         class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
577                         /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
578                                 class->name_space, class->name);*/
579                         if (bitmap != default_bitmap)
580                                 g_free (bitmap);
581                 }
582 #endif
583         } else {
584                 /*static int count = 0;
585                 if (count++ > 58)
586                         return;*/
587                 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set);
588 #ifdef HAVE_BOEHM_GC
589                 /* It seems there are issues when the bitmap doesn't fit: play it safe */
590                 if (max_set >= 30) {
591                         /*g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);*/
592                         if (bitmap != default_bitmap)
593                                 g_free (bitmap);
594                         return;
595                 }
596 #endif
597                 class->gc_descr = (gpointer)MAKE_DESCRIPTOR (bitmap, max_set + 1, class->instance_size);
598                 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
599                 if (bitmap != default_bitmap)
600                         g_free (bitmap);
601         }
602 }
603
604 /**
605  * field_is_special_static:
606  * @fklass: The MonoClass to look up.
607  * @field: The MonoClassField describing the field.
608  *
609  * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
610  * SPECIAL_STATIC_NONE otherwise.
611  */
612 static gint32
613 field_is_special_static (MonoClass *fklass, MonoClassField *field)
614 {
615         MonoCustomAttrInfo *ainfo;
616         int i;
617         ainfo = mono_custom_attrs_from_field (fklass, field);
618         if (!ainfo)
619                 return FALSE;
620         for (i = 0; i < ainfo->num_attrs; ++i) {
621                 MonoClass *klass = ainfo->attrs [i].ctor->klass;
622                 if (klass->image == mono_defaults.corlib) {
623                         if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
624                                 mono_custom_attrs_free (ainfo);
625                                 return SPECIAL_STATIC_THREAD;
626                         }
627                         else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
628                                 mono_custom_attrs_free (ainfo);
629                                 return SPECIAL_STATIC_CONTEXT;
630                         }
631                 }
632         }
633         mono_custom_attrs_free (ainfo);
634         return SPECIAL_STATIC_NONE;
635 }
636
637 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class);
638
639 /**
640  * mono_class_vtable:
641  * @domain: the application domain
642  * @class: the class to initialize
643  *
644  * VTables are domain specific because we create domain specific code, and 
645  * they contain the domain specific static class data.
646  */
647 MonoVTable *
648 mono_class_vtable (MonoDomain *domain, MonoClass *class)
649 {
650         MonoClassRuntimeInfo *runtime_info;
651
652         g_assert (class);
653
654         /* this check can be inlined in jitted code, too */
655         runtime_info = class->runtime_info;
656         if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
657                 return runtime_info->domain_vtables [domain->domain_id];
658         return mono_class_create_runtime_vtable (domain, class);
659 }
660
661 static MonoVTable *
662 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
663 {
664         MonoVTable *vt;
665         MonoClassRuntimeInfo *runtime_info, *old_info;
666         MonoClassField *field;
667         char *t;
668         int i;
669         gboolean inited = FALSE;
670         guint32 vtable_size;
671         guint32 cindex;
672         guint32 constant_cols [MONO_CONSTANT_SIZE];
673         gpointer iter;
674
675         mono_domain_lock (domain);
676         runtime_info = class->runtime_info;
677         if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
678                 mono_domain_unlock (domain);
679                 return runtime_info->domain_vtables [domain->domain_id];
680         }
681         if (!class->inited)
682                 mono_class_init (class);
683
684         mono_stats.used_class_count++;
685         mono_stats.class_vtable_size += sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
686
687         vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
688
689         vt = mono_mempool_alloc0 (domain->mp,  vtable_size);
690
691         vt->klass = class;
692         vt->rank = class->rank;
693         vt->domain = domain;
694
695         mono_class_compute_gc_descriptor (class);
696                 /*
697                  * We can't use typed allocation in the non-root domains, since the
698                  * collector needs the GC descriptor stored in the vtable even after
699                  * the mempool containing the vtable is destroyed when the domain is
700                  * unloaded. An alternative might be to allocate vtables in the GC
701                  * heap, but this does not seem to work (it leads to crashes inside
702                  * libgc). If that approach is tried, two gc descriptors need to be
703                  * allocated for each class: one for the root domain, and one for all
704                  * other domains. The second descriptor should contain a bit for the
705                  * vtable field in MonoObject, since we can no longer assume the 
706                  * vtable is reachable by other roots after the appdomain is unloaded.
707                  */
708 #ifdef HAVE_BOEHM_GC
709         if (domain != mono_get_root_domain ())
710                 vt->gc_descr = GC_NO_DESCRIPTOR;
711         else
712 #endif
713                 vt->gc_descr = class->gc_descr;
714
715         if (class->class_size) {
716                 if (class->has_static_refs)
717                         vt->data = mono_gc_alloc_fixed (class->class_size, NULL);
718                 else
719                         vt->data = mono_mempool_alloc0 (domain->mp, class->class_size);
720                 mono_g_hash_table_insert (domain->static_data_hash, class, vt->data);
721                 mono_stats.class_static_data_size += class->class_size;
722         }
723
724         cindex = -1;
725         iter = NULL;
726         while ((field = mono_class_get_fields (class, &iter))) {
727                 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
728                         continue;
729                 if (mono_field_is_deleted (field))
730                         continue;
731                 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
732                         gint32 special_static = field_is_special_static (class, field);
733                         if (special_static != SPECIAL_STATIC_NONE) {
734                                 guint32 size, offset;
735                                 int align;
736                                 size = mono_type_size (field->type, &align);
737                                 offset = mono_alloc_special_static_data (special_static, size, align);
738                                 if (!domain->special_static_fields)
739                                         domain->special_static_fields = g_hash_table_new (NULL, NULL);
740                                 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
741                                 continue;
742                         }
743                 }
744                 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
745                         MonoClass *fklass = mono_class_from_mono_type (field->type);
746                         g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
747                         t = (char*)vt->data + field->offset;
748                         if (fklass->valuetype) {
749                                 memcpy (t, field->data, mono_class_value_size (fklass, NULL));
750                         } else {
751                                 /* it's a pointer type: add check */
752                                 g_assert (fklass->byval_arg.type == MONO_TYPE_PTR);
753                                 *t = *(char *)field->data;
754                         }
755                         continue;
756                 }
757                 if (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
758                         continue;
759
760                 /* later do this only on demand if needed */
761                 if (!field->data) {
762                         cindex = mono_metadata_get_constant_index (class->image, mono_class_get_field_token (field), cindex + 1);
763                         g_assert (cindex);
764                         g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
765
766                         mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
767                         field->def_type = constant_cols [MONO_CONSTANT_TYPE];
768                         field->data = (gpointer)mono_metadata_blob_heap (class->image, constant_cols [MONO_CONSTANT_VALUE]);
769                 }
770                 
771         }
772
773         vt->max_interface_id = class->max_interface_id;
774         
775         vt->interface_offsets = mono_mempool_alloc0 (domain->mp, 
776                 sizeof (gpointer) * (class->max_interface_id + 1));
777
778         /* initialize interface offsets */
779         for (i = 0; i <= class->max_interface_id; ++i) {
780                 int slot = class->interface_offsets [i];
781                 if (slot >= 0)
782                         vt->interface_offsets [i] = &(vt->vtable [slot]);
783         }
784
785         /* 
786          * arch_create_jit_trampoline () can recursively call this function again
787          * because it compiles icall methods right away.
788          */
789         /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
790          * as we change the code in appdomain.c to invalidate vtables by
791          * looking at the possible MonoClasses created for the domain.
792          * Or we can reuse static_data_hash, by using vtable as a key
793          * and always inserting into that hash.
794          */
795         g_hash_table_insert (domain->class_vtable_hash, class, vt);
796         /* class->runtime_info is protected by the loader lock, both when
797          * it it enlarged and when it is stored info.
798          */
799         mono_loader_lock ();
800         old_info = class->runtime_info;
801         if (old_info && old_info->max_domain >= domain->domain_id) {
802                 /* someone already created a large enough runtime info */
803                 old_info->domain_vtables [domain->domain_id] = vt;
804         } else {
805                 int new_size = domain->domain_id;
806                 if (old_info)
807                         new_size = MAX (new_size, old_info->max_domain);
808                 new_size++;
809                 /* make the new size a power of two */
810                 i = 2;
811                 while (new_size > i)
812                         i <<= 1;
813                 new_size = i;
814                 /* this is a bounded memory retention issue: may want to 
815                  * handle it differently when we'll have a rcu-like system.
816                  */
817                 runtime_info = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoClassRuntimeInfo) + new_size * sizeof (gpointer));
818                 runtime_info->max_domain = new_size - 1;
819                 /* copy the stuff from the older info */
820                 if (old_info) {
821                         memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
822                 }
823                 runtime_info->domain_vtables [domain->domain_id] = vt;
824                 /* keep this last (add membarrier) */
825                 class->runtime_info = runtime_info;
826         }
827         mono_loader_unlock ();
828
829         /* initialize vtable */
830         if (init_vtable_func)
831                 inited = init_vtable_func (vt);
832
833         if (!inited) {
834                 mono_class_setup_vtable (class);
835
836                 for (i = 0; i < class->vtable_size; ++i) {
837                         MonoMethod *cm;
838
839                         if ((cm = class->vtable [i])) {
840                                 if (mono_method_signature (cm)->generic_param_count)
841                                         vt->vtable [i] = cm;
842                                 else
843                                         vt->vtable [i] = arch_create_jit_trampoline (cm);
844                         }
845                 }
846         }
847
848         mono_domain_unlock (domain);
849
850         /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
851         if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND)) {
852                 MonoException *exc = mono_class_get_exception_for_failure (class);
853                 g_assert (exc);
854                 mono_raise_exception (exc);
855         }
856
857         /* make sure the the parent is initialized */
858         if (class->parent)
859                 mono_class_vtable (domain, class->parent);
860
861         vt->type = mono_type_get_object (domain, &class->byval_arg);
862         if (class->contextbound)
863                 vt->remote = 1;
864         else
865                 vt->remote = 0;
866
867         return vt;
868 }
869
870 /**
871  * mono_class_proxy_vtable:
872  * @domain: the application domain
873  * @remove_class: the remote class
874  *
875  * Creates a vtable for transparent proxies. It is basically
876  * a copy of the real vtable of the class wrapped in @remote_class,
877  * but all function pointers invoke the remoting functions, and
878  * vtable->klass points to the transparent proxy class, and not to @class.
879  */
880 static MonoVTable *
881 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
882 {
883         MonoVTable *vt, *pvt;
884         int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
885         MonoClass *k;
886         GSList *extra_interfaces = NULL;
887         MonoClass *class = remote_class->proxy_class;
888
889         vt = mono_class_vtable (domain, class);
890         max_interface_id = vt->max_interface_id;
891         
892         /* Calculate vtable space for extra interfaces */
893         for (j = 0; j < remote_class->interface_count; j++) {
894                 MonoClass* iclass = remote_class->interfaces[j];
895                 GPtrArray *ifaces;
896                 int method_count;
897
898                 if (iclass->interface_id <= class->max_interface_id && class->interface_offsets[iclass->interface_id] != -1) 
899                         continue;       /* interface implemented by the class */
900                 if (g_slist_find (extra_interfaces, iclass))
901                         continue;
902                         
903                 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
904                 
905                 method_count = mono_class_num_methods (iclass);
906         
907                 ifaces = mono_class_get_implemented_interfaces (iclass);
908                 if (ifaces) {
909                         for (i = 0; i < ifaces->len; ++i) {
910                                 MonoClass *ic = g_ptr_array_index (ifaces, i);
911                                 if (ic->interface_id <= class->max_interface_id && class->interface_offsets[ic->interface_id] != -1) 
912                                         continue;       /* interface implemented by the class */
913                                 if (g_slist_find (extra_interfaces, ic))
914                                         continue;
915                                 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
916                                 method_count += mono_class_num_methods (ic);
917                         }
918                         g_ptr_array_free (ifaces, TRUE);
919                 }
920
921                 extra_interface_vtsize += method_count * sizeof (gpointer);
922                 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
923         }
924
925         vtsize = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
926
927         mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
928
929         pvt = mono_mempool_alloc (domain->mp, vtsize + extra_interface_vtsize);
930         memcpy (pvt, vt, vtsize);
931
932         pvt->klass = mono_defaults.transparent_proxy_class;
933         /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
934         pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
935
936         /* initialize vtable */
937         mono_class_setup_vtable (class);
938         for (i = 0; i < class->vtable_size; ++i) {
939                 MonoMethod *cm;
940                     
941                 if ((cm = class->vtable [i]))
942                         pvt->vtable [i] = arch_create_remoting_trampoline (cm, target_type);
943         }
944
945         if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
946                 /* create trampolines for abstract methods */
947                 for (k = class; k; k = k->parent) {
948                         MonoMethod* m;
949                         gpointer iter = NULL;
950                         while ((m = mono_class_get_methods (k, &iter)))
951                                 if (!pvt->vtable [m->slot])
952                                         pvt->vtable [m->slot] = arch_create_remoting_trampoline (m, target_type);
953                 }
954         }
955
956         pvt->max_interface_id = max_interface_id;
957         pvt->interface_offsets = mono_mempool_alloc0 (domain->mp, 
958                         sizeof (gpointer) * (max_interface_id + 1));
959
960         /* initialize interface offsets */
961         for (i = 0; i <= class->max_interface_id; ++i) {
962                 int slot = class->interface_offsets [i];
963                 if (slot >= 0)
964                         pvt->interface_offsets [i] = &(pvt->vtable [slot]);
965         }
966
967         if (extra_interfaces) {
968                 int slot = class->vtable_size;
969                 MonoClass* interf;
970                 gpointer iter;
971                 MonoMethod* cm;
972                 GSList *list_item;
973
974                 /* Create trampolines for the methods of the interfaces */
975                 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
976                         interf = list_item->data;
977                         pvt->interface_offsets [interf->interface_id] = &pvt->vtable [slot];
978
979                         iter = NULL;
980                         j = 0;
981                         while ((cm = mono_class_get_methods (interf, &iter)))
982                                 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (cm, target_type);
983                         
984                         slot += mono_class_num_methods (interf);
985                 }
986                 g_slist_free (extra_interfaces);
987         }
988
989         return pvt;
990 }
991
992 /**
993  * create_remote_class_key:
994  * Creates an array of pointers that can be used as a hash key for a remote class.
995  * The first element of the array is the number of pointers.
996  */
997 static gpointer*
998 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
999 {
1000         gpointer *key;
1001         int i, j;
1002         
1003         if (remote_class == NULL) {
1004                 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1005                         key = g_malloc (sizeof(gpointer) * 3);
1006                         key [0] = GINT_TO_POINTER (2);
1007                         key [1] = mono_defaults.marshalbyrefobject_class;
1008                         key [2] = extra_class;
1009                 } else {
1010                         key = g_malloc (sizeof(gpointer) * 2);
1011                         key [0] = GINT_TO_POINTER (1);
1012                         key [1] = extra_class;
1013                 }
1014         } else {
1015                 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
1016                         key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
1017                         key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
1018                         key [1] = remote_class->proxy_class;
1019
1020                         // Keep the list of interfaces sorted
1021                         for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
1022                                 if (extra_class && remote_class->interfaces [i] > extra_class) {
1023                                         key [j++] = extra_class;
1024                                         extra_class = NULL;
1025                                 }
1026                                 key [j] = remote_class->interfaces [i];
1027                         }
1028                         if (extra_class)
1029                                 key [j] = extra_class;
1030                 } else {
1031                         // Replace the old class. The interface list is the same
1032                         key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
1033                         key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
1034                         key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
1035                         for (i = 0; i < remote_class->interface_count; i++)
1036                                 key [2 + i] = remote_class->interfaces [i];
1037                 }
1038         }
1039         
1040         return key;
1041 }
1042
1043 /**
1044  * mono_remote_class:
1045  * @domain: the application domain
1046  * @class_name: name of the remote class
1047  *
1048  * Creates and initializes a MonoRemoteClass object for a remote type. 
1049  * 
1050  */
1051 MonoRemoteClass*
1052 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
1053 {
1054         MonoRemoteClass *rc;
1055         gpointer* key;
1056         
1057         key = create_remote_class_key (NULL, proxy_class);
1058         
1059         mono_domain_lock (domain);
1060         rc = mono_g_hash_table_lookup (domain->proxy_vtable_hash, key);
1061
1062         if (rc) {
1063                 g_free (key);
1064                 mono_domain_unlock (domain);
1065                 return rc;
1066         }
1067
1068         if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1069                 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*));
1070                 rc->interface_count = 1;
1071                 rc->interfaces [0] = proxy_class;
1072                 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
1073         } else {
1074                 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass));
1075                 rc->interface_count = 0;
1076                 rc->proxy_class = proxy_class;
1077         }
1078         
1079         rc->default_vtable = NULL;
1080         rc->xdomain_vtable = NULL;
1081         rc->proxy_class_name = mono_string_to_utf8 (class_name);
1082
1083         mono_g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1084
1085         mono_domain_unlock (domain);
1086         return rc;
1087 }
1088
1089 /**
1090  * clone_remote_class:
1091  * Creates a copy of the remote_class, adding the provided class or interface
1092  */
1093 static MonoRemoteClass*
1094 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
1095 {
1096         MonoRemoteClass *rc;
1097         gpointer* key;
1098         
1099         key = create_remote_class_key (remote_class, extra_class);
1100         rc = mono_g_hash_table_lookup (domain->proxy_vtable_hash, key);
1101         if (rc != NULL) {
1102                 g_free (key);
1103                 return rc;
1104         }
1105
1106         if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1107                 int i,j;
1108                 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * (remote_class->interface_count + 1));
1109                 rc->proxy_class = remote_class->proxy_class;
1110                 rc->interface_count = remote_class->interface_count + 1;
1111                 
1112                 // Keep the list of interfaces sorted, since the hash key of
1113                 // the remote class depends on this
1114                 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
1115                         if (remote_class->interfaces [i] > extra_class && i == j)
1116                                 rc->interfaces [j++] = extra_class;
1117                         rc->interfaces [j] = remote_class->interfaces [i];
1118                 }
1119                 if (i == j)
1120                         rc->interfaces [j] = extra_class;
1121         } else {
1122                 // Replace the old class. The interface array is the same
1123                 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * remote_class->interface_count);
1124                 rc->proxy_class = extra_class;
1125                 rc->interface_count = remote_class->interface_count;
1126                 if (rc->interface_count > 0)
1127                         memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
1128         }
1129         
1130         rc->default_vtable = NULL;
1131         rc->xdomain_vtable = NULL;
1132         rc->proxy_class_name = remote_class->proxy_class_name;
1133
1134         mono_g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1135
1136         return rc;
1137 }
1138
1139 gpointer
1140 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
1141 {
1142         mono_domain_lock (domain);
1143         if (rp->target_domain_id != -1) {
1144                 if (remote_class->xdomain_vtable == NULL)
1145                         remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
1146                 mono_domain_unlock (domain);
1147                 return remote_class->xdomain_vtable;
1148         }
1149         if (remote_class->default_vtable == NULL)
1150                 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
1151         
1152         mono_domain_unlock (domain);
1153         return remote_class->default_vtable;
1154 }
1155
1156 /**
1157  * mono_upgrade_remote_class:
1158  * @domain: the application domain
1159  * @tproxy: the proxy whose remote class has to be upgraded.
1160  * @klass: class to which the remote class can be casted.
1161  *
1162  * Updates the vtable of the remote class by adding the necessary method slots
1163  * and interface offsets so it can be safely casted to klass. klass can be a
1164  * class or an interface.
1165  */
1166 void
1167 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
1168 {
1169         MonoTransparentProxy *tproxy;
1170         MonoRemoteClass *remote_class;
1171         gboolean redo_vtable;
1172
1173         mono_domain_lock (domain);
1174
1175         tproxy = (MonoTransparentProxy*) proxy_object;
1176         remote_class = tproxy->remote_class;
1177         
1178         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1179                 int i;
1180                 redo_vtable = TRUE;
1181                 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
1182                         if (remote_class->interfaces [i] == klass)
1183                                 redo_vtable = FALSE;
1184         }
1185         else {
1186                 redo_vtable = (remote_class->proxy_class != klass);
1187         }
1188
1189         if (redo_vtable) {
1190                 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
1191                 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
1192         }
1193         
1194         mono_domain_unlock (domain);
1195 }
1196
1197
1198 /**
1199  * mono_object_get_virtual_method:
1200  * @obj: object to operate on.
1201  * @method: method 
1202  *
1203  * Retrieves the MonoMethod that would be called on obj if obj is passed as
1204  * the instance of a callvirt of method.
1205  */
1206 MonoMethod*
1207 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
1208 {
1209         MonoClass *klass;
1210         MonoMethod **vtable;
1211         gboolean is_proxy;
1212         MonoMethod *res = NULL;
1213
1214         klass = mono_object_class (obj);
1215         if (klass == mono_defaults.transparent_proxy_class) {
1216                 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
1217                 is_proxy = TRUE;
1218         } else {
1219                 is_proxy = FALSE;
1220         }
1221
1222         if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
1223                         return method;
1224
1225         mono_class_setup_vtable (klass);
1226         vtable = klass->vtable;
1227
1228         /* check method->slot is a valid index: perform isinstance? */
1229         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1230                 if (!is_proxy)
1231                         res = vtable [klass->interface_offsets [method->klass->interface_id] + method->slot];
1232         } else {
1233                 if (method->slot != -1)
1234                         res = vtable [method->slot];
1235         }
1236
1237         if (is_proxy) {
1238                 if (!res) res = method;   /* It may be an interface or abstract class method */
1239                 res = mono_marshal_get_remoting_invoke (res);
1240         }
1241
1242         g_assert (res);
1243         
1244         return res;
1245 }
1246
1247 static MonoObject*
1248 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
1249 {
1250         g_error ("runtime invoke called on uninitialized runtime");
1251         return NULL;
1252 }
1253
1254 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
1255
1256 /**
1257  * mono_runtime_invoke:
1258  * @method: method to invoke
1259  * @obJ: object instance
1260  * @params: arguments to the method
1261  * @exc: exception information.
1262  *
1263  * Invokes the method represented by @method on the object @obj.
1264  *
1265  * obj is the 'this' pointer, it should be NULL for static
1266  * methods, a MonoObject* for object instances and a pointer to
1267  * the value type for value types.
1268  *
1269  * The params array contains the arguments to the method with the
1270  * same convention: MonoObject* pointers for object instances and
1271  * pointers to the value type otherwise. 
1272  * 
1273  * From unmanaged code you'll usually use the
1274  * mono_runtime_invoke() variant.
1275  *
1276  * Note that this function doesn't handle virtual methods for
1277  * you, it will exec the exact method you pass: we still need to
1278  * expose a function to lookup the derived class implementation
1279  * of a virtual method (there are examples of this in the code,
1280  * though).
1281  * 
1282  * You can pass NULL as the exc argument if you don't want to
1283  * catch exceptions, otherwise, *exc will be set to the exception
1284  * thrown, if any.  if an exception is thrown, you can't use the
1285  * MonoObject* result from the function.
1286  * 
1287  * If the method returns a value type, it is boxed in an object
1288  * reference.
1289  */
1290 MonoObject*
1291 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
1292 {
1293         return default_mono_runtime_invoke (method, obj, params, exc);
1294 }
1295
1296 static void
1297 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
1298 {
1299         int t;
1300         if (type->byref) {
1301                 gpointer *p = (gpointer*)dest;
1302                 *p = value;
1303                 return;
1304         }
1305         t = type->type;
1306 handle_enum:
1307         switch (t) {
1308         case MONO_TYPE_BOOLEAN:
1309         case MONO_TYPE_I1:
1310         case MONO_TYPE_U1: {
1311                 guint8 *p = (guint8*)dest;
1312                 *p = value ? *(guint8*)value : 0;
1313                 return;
1314         }
1315         case MONO_TYPE_I2:
1316         case MONO_TYPE_U2:
1317         case MONO_TYPE_CHAR: {
1318                 guint16 *p = (guint16*)dest;
1319                 *p = value ? *(guint16*)value : 0;
1320                 return;
1321         }
1322 #if SIZEOF_VOID_P == 4
1323         case MONO_TYPE_I:
1324         case MONO_TYPE_U:
1325 #endif
1326         case MONO_TYPE_I4:
1327         case MONO_TYPE_U4: {
1328                 gint32 *p = (gint32*)dest;
1329                 *p = value ? *(gint32*)value : 0;
1330                 return;
1331         }
1332 #if SIZEOF_VOID_P == 8
1333         case MONO_TYPE_I:
1334         case MONO_TYPE_U:
1335 #endif
1336         case MONO_TYPE_I8:
1337         case MONO_TYPE_U8: {
1338                 gint64 *p = (gint64*)dest;
1339                 *p = value ? *(gint64*)value : 0;
1340                 return;
1341         }
1342         case MONO_TYPE_R4: {
1343                 float *p = (float*)dest;
1344                 *p = value ? *(float*)value : 0;
1345                 return;
1346         }
1347         case MONO_TYPE_R8: {
1348                 double *p = (double*)dest;
1349                 *p = value ? *(double*)value : 0;
1350                 return;
1351         }
1352         case MONO_TYPE_STRING:
1353         case MONO_TYPE_SZARRAY:
1354         case MONO_TYPE_CLASS:
1355         case MONO_TYPE_OBJECT:
1356         case MONO_TYPE_ARRAY:
1357         case MONO_TYPE_PTR: {
1358                 gpointer *p = (gpointer*)dest;
1359                 *p = deref_pointer? *(gpointer*)value: value;
1360                 return;
1361         }
1362         case MONO_TYPE_VALUETYPE:
1363                 if (type->data.klass->enumtype) {
1364                         t = type->data.klass->enum_basetype->type;
1365                         goto handle_enum;
1366                 } else {
1367                         int size;
1368                         size = mono_class_value_size (type->data.klass, NULL);
1369                         if (value == NULL)
1370                                 memset (dest, 0, size);
1371                         else
1372                                 memcpy (dest, value, size);
1373                 }
1374                 return;
1375         default:
1376                 g_warning ("got type %x", type->type);
1377                 g_assert_not_reached ();
1378         }
1379 }
1380
1381 /**
1382  * mono_field_set_value:
1383  * @obj: Instance object
1384  * @field: MonoClassField describing the field to set
1385  * @value: The value to be set
1386  *
1387  * Sets the value of the field described by @field in the object instance @obj
1388  * to the value passed in @value.
1389  *
1390  * The value must be on the native format of the field type. 
1391  */
1392 void
1393 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
1394 {
1395         void *dest;
1396
1397         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
1398
1399         dest = (char*)obj + field->offset;
1400         set_value (field->type, dest, value, FALSE);
1401 }
1402
1403 /**
1404  * mono_field_static_set_value:
1405  * @field: MonoClassField describing the field to set
1406  * @value: The value to be set
1407  *
1408  * Sets the value of the static field described by @field
1409  * to the value passed in @value.
1410  *
1411  * The value must be on the native format of the field type. 
1412  */
1413 void
1414 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
1415 {
1416         void *dest;
1417
1418         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
1419         /* you cant set a constant! */
1420         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
1421         
1422         dest = (char*)vt->data + field->offset;
1423         set_value (field->type, dest, value, FALSE);
1424 }
1425
1426 /**
1427  * mono_field_get_value:
1428  * @obj: Object instance
1429  * @field: MonoClassField describing the field to fetch information from
1430  * @value: pointer to the location where the value will be stored
1431  *
1432  * Use this routine to get the value of the field @field in the object
1433  * passed.
1434  *
1435  * The pointer provided by value must be of the field type, for reference
1436  * types this is a MonoObject*, for value types its the actual pointer to
1437  * the value type.
1438  *
1439  * For example:
1440  *     int i;
1441  *     mono_field_get_value (obj, int_field, &i);
1442  */
1443 void
1444 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
1445 {
1446         void *src;
1447
1448         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
1449
1450         src = (char*)obj + field->offset;
1451         set_value (field->type, value, src, TRUE);
1452 }
1453
1454 /**
1455  * mono_field_get_value_object:
1456  * @domain: domain where the object will be created (if boxing)
1457  * @field: MonoClassField describing the field to fetch information from
1458  * @obj: The object instance for the field.
1459  *
1460  * Returns: a new MonoObject with the value from the given field.  If the
1461  * field represents a value type, the value is boxed.
1462  *
1463  */
1464 MonoObject *
1465 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
1466 {       
1467         MonoObject *o;
1468         MonoClass *klass;
1469         MonoVTable *vtable = NULL;
1470         gchar *v;
1471         gboolean is_static = FALSE;
1472         gboolean is_ref = FALSE;
1473
1474         switch (field->type->type) {
1475         case MONO_TYPE_STRING:
1476         case MONO_TYPE_OBJECT:
1477         case MONO_TYPE_CLASS:
1478         case MONO_TYPE_ARRAY:
1479         case MONO_TYPE_SZARRAY:
1480                 is_ref = TRUE;
1481                 break;
1482         case MONO_TYPE_U1:
1483         case MONO_TYPE_I1:
1484         case MONO_TYPE_BOOLEAN:
1485         case MONO_TYPE_U2:
1486         case MONO_TYPE_I2:
1487         case MONO_TYPE_CHAR:
1488         case MONO_TYPE_U:
1489         case MONO_TYPE_I:
1490         case MONO_TYPE_U4:
1491         case MONO_TYPE_I4:
1492         case MONO_TYPE_R4:
1493         case MONO_TYPE_U8:
1494         case MONO_TYPE_I8:
1495         case MONO_TYPE_R8:
1496         case MONO_TYPE_VALUETYPE:
1497                 is_ref = field->type->byref;
1498                 break;
1499         default:
1500                 g_error ("type 0x%x not handled in "
1501                          "mono_field_get_value_object", field->type->type);
1502                 return NULL;
1503         }
1504
1505         if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
1506                 is_static = TRUE;
1507                 vtable = mono_class_vtable (domain, field->parent);
1508                 if (!vtable->initialized)
1509                         mono_runtime_class_init (vtable);
1510         }
1511         
1512         if (is_ref) {
1513                 if (is_static) {
1514                         mono_field_static_get_value (vtable, field, &o);
1515                 } else {
1516                         mono_field_get_value (obj, field, &o);
1517                 }
1518                 return o;
1519         }
1520
1521         /* boxed value type */
1522         klass = mono_class_from_mono_type (field->type);
1523         o = mono_object_new (domain, klass);
1524         v = ((gchar *) o) + sizeof (MonoObject);
1525         if (is_static) {
1526                 mono_field_static_get_value (vtable, field, v);
1527         } else {
1528                 mono_field_get_value (obj, field, v);
1529         }
1530
1531         return o;
1532 }
1533
1534 int
1535 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
1536 {
1537         int retval = 0;
1538         const char *p = blob;
1539         mono_metadata_decode_blob_size (p, &p);
1540
1541         switch (type) {
1542         case MONO_TYPE_BOOLEAN:
1543         case MONO_TYPE_U1:
1544         case MONO_TYPE_I1:
1545                 *(guint8 *) value = *p;
1546                 break;
1547         case MONO_TYPE_CHAR:
1548         case MONO_TYPE_U2:
1549         case MONO_TYPE_I2:
1550                 *(guint16*) value = read16 (p);
1551                 break;
1552         case MONO_TYPE_U4:
1553         case MONO_TYPE_I4:
1554                 *(guint32*) value = read32 (p);
1555                 break;
1556         case MONO_TYPE_U8:
1557         case MONO_TYPE_I8:
1558                 *(guint64*) value = read64 (p);
1559                 break;
1560         case MONO_TYPE_R4:
1561                 readr4 (p, (float*) value);
1562                 break;
1563         case MONO_TYPE_R8:
1564                 readr8 (p, (double*) value);
1565                 break;
1566         case MONO_TYPE_STRING:
1567                 *(gpointer*) value = mono_ldstr_metdata_sig (domain, blob);
1568                 break;
1569         case MONO_TYPE_CLASS:
1570                 *(gpointer*) value = NULL;
1571                 break;
1572         default:
1573                 retval = -1;
1574                 g_warning ("type 0x%02x should not be in constant table", type);
1575         }
1576         return retval;
1577 }
1578
1579 static void
1580 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
1581 {
1582         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
1583         mono_get_constant_value_from_blob (domain, field->def_type, field->data, value);
1584 }
1585
1586 /**
1587  * mono_field_static_get_value:
1588  * @vt: vtable to the object
1589  * @field: MonoClassField describing the field to fetch information from
1590  * @value: where the value is returned
1591  *
1592  * Use this routine to get the value of the static field @field value.
1593  *
1594  * The pointer provided by value must be of the field type, for reference
1595  * types this is a MonoObject*, for value types its the actual pointer to
1596  * the value type.
1597  *
1598  * For example:
1599  *     int i;
1600  *     mono_field_static_get_value (vt, int_field, &i);
1601  */
1602 void
1603 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
1604 {
1605         void *src;
1606
1607         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
1608         
1609         if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
1610                 get_default_field_value (vt->domain, field, value);
1611                 return;
1612         }
1613
1614         src = (char*)vt->data + field->offset;
1615         set_value (field->type, value, src, TRUE);
1616 }
1617
1618 /**
1619  * mono_property_set_value:
1620  * @prop: MonoProperty to set
1621  * @obj: instance object on which to act
1622  * @params: parameters to pass to the propery
1623  * @exc: optional exception
1624  *
1625  * Invokes the property's set method with the given arguments on the
1626  * object instance obj (or NULL for static properties). 
1627  * 
1628  * You can pass NULL as the exc argument if you don't want to
1629  * catch exceptions, otherwise, *exc will be set to the exception
1630  * thrown, if any.  if an exception is thrown, you can't use the
1631  * MonoObject* result from the function.
1632  */
1633 void
1634 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
1635 {
1636         default_mono_runtime_invoke (prop->set, obj, params, exc);
1637 }
1638
1639 /**
1640  * mono_property_get_value:
1641  * @prop: MonoProperty to fetch
1642  * @obj: instance object on which to act
1643  * @params: parameters to pass to the propery
1644  * @exc: optional exception
1645  *
1646  * Invokes the property's get method with the given arguments on the
1647  * object instance obj (or NULL for static properties). 
1648  * 
1649  * You can pass NULL as the exc argument if you don't want to
1650  * catch exceptions, otherwise, *exc will be set to the exception
1651  * thrown, if any.  if an exception is thrown, you can't use the
1652  * MonoObject* result from the function.
1653  *
1654  * Returns: the value from invoking the get method on the property.
1655  */
1656 MonoObject*
1657 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
1658 {
1659         return default_mono_runtime_invoke (prop->get, obj, params, exc);
1660 }
1661
1662
1663 /**
1664  * mono_get_delegate_invoke:
1665  * @klass: The delegate class
1666  *
1667  * Returns: the MonoMethod for the "Invoke" method in the delegate klass
1668  */
1669 MonoMethod *
1670 mono_get_delegate_invoke (MonoClass *klass)
1671 {
1672         MonoMethod *im;
1673
1674         im = mono_class_get_method_from_name (klass, "Invoke", -1);
1675         g_assert (im);
1676
1677         return im;
1678 }
1679
1680 /**
1681  * mono_runtime_delegate_invoke:
1682  * @delegate: pointer to a delegate object.
1683  * @params: parameters for the delegate.
1684  * @exc: Pointer to the exception result.
1685  *
1686  * Invokes the delegate method @delegate with the parameters provided.
1687  *
1688  * You can pass NULL as the exc argument if you don't want to
1689  * catch exceptions, otherwise, *exc will be set to the exception
1690  * thrown, if any.  if an exception is thrown, you can't use the
1691  * MonoObject* result from the function.
1692  */
1693 MonoObject*
1694 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
1695 {
1696         MonoMethod *im;
1697
1698         im = mono_get_delegate_invoke (delegate->vtable->klass);
1699         g_assert (im);
1700
1701         return mono_runtime_invoke (im, delegate, params, exc);
1702 }
1703
1704 static char **main_args = NULL;
1705 static int num_main_args;
1706
1707 /**
1708  * mono_runtime_get_main_args:
1709  *
1710  * Returns: a MonoArray with the arguments passed to the main program
1711  */
1712 MonoArray*
1713 mono_runtime_get_main_args (void)
1714 {
1715         MonoArray *res;
1716         int i;
1717         MonoDomain *domain = mono_domain_get ();
1718
1719         if (!main_args)
1720                 return NULL;
1721
1722         res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
1723
1724         for (i = 0; i < num_main_args; ++i)
1725                 mono_array_set (res, gpointer, i, mono_string_new (domain, main_args [i]));
1726
1727         return res;
1728 }
1729
1730 static void
1731 fire_process_exit_event (void)
1732 {
1733         MonoClassField *field;
1734         MonoDomain *domain = mono_domain_get ();
1735         gpointer pa [2];
1736         MonoObject *delegate, *exc;
1737         
1738         field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
1739         g_assert (field);
1740
1741         if (domain != mono_get_root_domain ())
1742                 return;
1743
1744         delegate = *(MonoObject **)(((char *)domain->domain) + field->offset); 
1745         if (delegate == NULL)
1746                 return;
1747
1748         pa [0] = domain;
1749         pa [1] = NULL;
1750         mono_runtime_delegate_invoke (delegate, pa, &exc);
1751 }
1752
1753 /**
1754  * mono_runtime_run_main:
1755  * @method: the method to start the application with (usually Main)
1756  * @argc: number of arguments from the command line
1757  * @argv: array of strings from the command line
1758  * @exc: excetption results
1759  *
1760  * Execute a standard Main() method (argc/argv contains the
1761  * executable name). This method also sets the command line argument value
1762  * needed by System.Environment.
1763  *
1764  * 
1765  */
1766 int
1767 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
1768                        MonoObject **exc)
1769 {
1770         int i;
1771         MonoArray *args = NULL;
1772         MonoDomain *domain = mono_domain_get ();
1773         gchar *utf8_fullpath;
1774         int result;
1775
1776         mono_thread_set_main (mono_thread_current ());
1777
1778         main_args = g_new0 (char*, argc);
1779         num_main_args = argc;
1780
1781         if (!g_path_is_absolute (argv [0])) {
1782                 gchar *basename = g_path_get_basename (argv [0]);
1783                 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
1784                                                     basename,
1785                                                     NULL);
1786
1787                 utf8_fullpath = mono_utf8_from_external (fullpath);
1788                 if(utf8_fullpath == NULL) {
1789                         /* Printing the arg text will cause glib to
1790                          * whinge about "Invalid UTF-8", but at least
1791                          * its relevant, and shows the problem text
1792                          * string.
1793                          */
1794                         g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
1795                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1796                         exit (-1);
1797                 }
1798
1799                 g_free (fullpath);
1800                 g_free (basename);
1801         } else {
1802                 utf8_fullpath = mono_utf8_from_external (argv[0]);
1803                 if(utf8_fullpath == NULL) {
1804                         g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
1805                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1806                         exit (-1);
1807                 }
1808         }
1809
1810         main_args [0] = utf8_fullpath;
1811
1812         for (i = 1; i < argc; ++i) {
1813                 gchar *utf8_arg;
1814
1815                 utf8_arg=mono_utf8_from_external (argv[i]);
1816                 if(utf8_arg==NULL) {
1817                         /* Ditto the comment about Invalid UTF-8 here */
1818                         g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
1819                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1820                         exit (-1);
1821                 }
1822
1823                 main_args [i] = utf8_arg;
1824         }
1825         argc--;
1826         argv++;
1827         if (mono_method_signature (method)->param_count) {
1828                 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
1829                 for (i = 0; i < argc; ++i) {
1830                         /* The encodings should all work, given that
1831                          * we've checked all these args for the
1832                          * main_args array.
1833                          */
1834                         gchar *str = mono_utf8_from_external (argv [i]);
1835                         MonoString *arg = mono_string_new (domain, str);
1836                         mono_array_set (args, gpointer, i, arg);
1837                         g_free (str);
1838                 }
1839         } else {
1840                 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
1841         }
1842         
1843         mono_assembly_set_main (method->klass->image->assembly);
1844
1845         result = mono_runtime_exec_main (method, args, exc);
1846         fire_process_exit_event ();
1847         return result;
1848 }
1849
1850 /* Used in mono_unhandled_exception */
1851 static MonoObject *
1852 create_unhandled_exception_eventargs (MonoObject *exc)
1853 {
1854         MonoClass *klass;
1855         gpointer args [2];
1856         MonoMethod *method = NULL;
1857         MonoBoolean is_terminating = TRUE;
1858         MonoObject *obj;
1859
1860         klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
1861         g_assert (klass);
1862
1863         mono_class_init (klass);
1864
1865         /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
1866         method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
1867         g_assert (method);
1868
1869         args [0] = exc;
1870         args [1] = &is_terminating;
1871
1872         obj = mono_object_new (mono_domain_get (), klass);
1873         mono_runtime_invoke (method, obj, args, NULL);
1874
1875         return obj;
1876 }
1877
1878 /**
1879  * mono_unhandled_exception:
1880  * @exc: exception thrown
1881  *
1882  * This is a VM internal routine.
1883  *
1884  * We call this function when we detect an unhandled exception
1885  * in the default domain.
1886  *
1887  * It invokes the * UnhandledException event in AppDomain or prints
1888  * a warning to the console 
1889  */
1890 void
1891 mono_unhandled_exception (MonoObject *exc)
1892 {
1893         MonoDomain *domain = mono_domain_get ();
1894         MonoClassField *field;
1895         MonoObject *delegate;
1896
1897         field=mono_class_get_field_from_name(mono_defaults.appdomain_class, 
1898                                              "UnhandledException");
1899         g_assert (field);
1900
1901         if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
1902                 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset); 
1903
1904                 /* set exitcode only in the main thread */
1905                 if (mono_thread_current () == main_thread)
1906                         mono_environment_exitcode_set (1);
1907                 if (domain != mono_get_root_domain () || !delegate) {
1908                         mono_print_unhandled_exception (exc);
1909                 } else {
1910                         MonoObject *e = NULL;
1911                         gpointer pa [2];
1912
1913                         pa [0] = domain->domain;
1914                         pa [1] = create_unhandled_exception_eventargs (exc);
1915                         mono_runtime_delegate_invoke (delegate, pa, &e);
1916                         
1917                         if (e) {
1918                                 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
1919                                 g_warning ("exception inside UnhandledException handler: %s\n", msg);
1920                                 g_free (msg);
1921                         }
1922                 }
1923         }
1924 }
1925
1926 /*
1927  * Launch a new thread to execute a function
1928  *
1929  * main_func is called back from the thread with main_args as the
1930  * parameter.  The callback function is expected to start Main()
1931  * eventually.  This function then waits for all managed threads to
1932  * finish.
1933  * It is not necesseray anymore to execute managed code in a subthread,
1934  * so this function should not be used anymore by default: just
1935  * execute the code and then call mono_thread_manage ().
1936  */
1937 void
1938 mono_runtime_exec_managed_code (MonoDomain *domain,
1939                                 MonoMainThreadFunc main_func,
1940                                 gpointer main_args)
1941 {
1942         mono_thread_create (domain, main_func, main_args);
1943
1944         mono_thread_manage ();
1945 }
1946
1947 /*
1948  * Execute a standard Main() method (args doesn't contain the
1949  * executable name).
1950  */
1951 int
1952 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
1953 {
1954         MonoDomain *domain;
1955         gpointer pa [1];
1956         int rval;
1957
1958         g_assert (args);
1959
1960         pa [0] = args;
1961
1962         domain = mono_object_domain (args);
1963         if (!domain->entry_assembly) {
1964                 gchar *str;
1965                 gchar *config_suffix;
1966                 MonoAssembly *assembly;
1967
1968                 assembly = method->klass->image->assembly;
1969                 domain->entry_assembly = assembly;
1970                 domain->setup->application_base = mono_string_new (domain, assembly->basedir);
1971
1972                 config_suffix = g_strconcat (assembly->aname.name, ".exe.config", NULL);
1973                 str = g_build_filename (assembly->basedir, config_suffix, NULL);
1974                 g_free (config_suffix);
1975                 domain->setup->configuration_file = mono_string_new (domain, str);
1976                 g_free (str);
1977         }
1978
1979         /* FIXME: check signature of method */
1980         if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
1981                 MonoObject *res;
1982                 res = mono_runtime_invoke (method, NULL, pa, exc);
1983                 if (!exc || !*exc)
1984                         rval = *(guint32 *)((char *)res + sizeof (MonoObject));
1985                 else
1986                         rval = -1;
1987
1988                 mono_environment_exitcode_set (rval);
1989         } else {
1990                 mono_runtime_invoke (method, NULL, pa, exc);
1991                 if (!exc || !*exc)
1992                         rval = 0;
1993                 else {
1994                         /* If the return type of Main is void, only
1995                          * set the exitcode if an exception was thrown
1996                          * (we don't want to blow away an
1997                          * explicitly-set exit code)
1998                          */
1999                         rval = -1;
2000                         mono_environment_exitcode_set (rval);
2001                 }
2002         }
2003
2004         return rval;
2005 }
2006
2007 /**
2008  * mono_install_runtime_invoke:
2009  * @func: Function to install
2010  *
2011  * This is a VM internal routine
2012  */
2013 void
2014 mono_install_runtime_invoke (MonoInvokeFunc func)
2015 {
2016         default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
2017 }
2018
2019 /**
2020  * mono_runtime_invoke_array:
2021  * @method: method to invoke
2022  * @obJ: object instance
2023  * @params: arguments to the method
2024  * @exc: exception information.
2025  *
2026  * Invokes the method represented by @method on the object @obj.
2027  *
2028  * obj is the 'this' pointer, it should be NULL for static
2029  * methods, a MonoObject* for object instances and a pointer to
2030  * the value type for value types.
2031  *
2032  * The params array contains the arguments to the method with the
2033  * same convention: MonoObject* pointers for object instances and
2034  * pointers to the value type otherwise. The _invoke_array
2035  * variant takes a C# object[] as the params argument (MonoArray
2036  * *params): in this case the value types are boxed inside the
2037  * respective reference representation.
2038  * 
2039  * From unmanaged code you'll usually use the
2040  * mono_runtime_invoke() variant.
2041  *
2042  * Note that this function doesn't handle virtual methods for
2043  * you, it will exec the exact method you pass: we still need to
2044  * expose a function to lookup the derived class implementation
2045  * of a virtual method (there are examples of this in the code,
2046  * though).
2047  * 
2048  * You can pass NULL as the exc argument if you don't want to
2049  * catch exceptions, otherwise, *exc will be set to the exception
2050  * thrown, if any.  if an exception is thrown, you can't use the
2051  * MonoObject* result from the function.
2052  * 
2053  * If the method returns a value type, it is boxed in an object
2054  * reference.
2055  */
2056 MonoObject*
2057 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
2058                            MonoObject **exc)
2059 {
2060         MonoMethodSignature *sig = mono_method_signature (method);
2061         gpointer *pa = NULL;
2062         int i;
2063                 
2064         if (NULL != params) {
2065                 pa = alloca (sizeof (gpointer) * mono_array_length (params));
2066                 for (i = 0; i < mono_array_length (params); i++) {
2067                         if (sig->params [i]->byref) {
2068                                 /* nothing to do */
2069                         }
2070
2071                         switch (sig->params [i]->type) {
2072                         case MONO_TYPE_U1:
2073                         case MONO_TYPE_I1:
2074                         case MONO_TYPE_BOOLEAN:
2075                         case MONO_TYPE_U2:
2076                         case MONO_TYPE_I2:
2077                         case MONO_TYPE_CHAR:
2078                         case MONO_TYPE_U:
2079                         case MONO_TYPE_I:
2080                         case MONO_TYPE_U4:
2081                         case MONO_TYPE_I4:
2082                         case MONO_TYPE_U8:
2083                         case MONO_TYPE_I8:
2084                         case MONO_TYPE_R4:
2085                         case MONO_TYPE_R8:
2086                         case MONO_TYPE_VALUETYPE:
2087                                 /* MS seems to create the objects if a null is passed in */
2088                                 if (! ((gpointer *)params->vector)[i])
2089                                         ((gpointer*)params->vector)[i] = mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i]));
2090                                 pa [i] = (char *)(((gpointer *)params->vector)[i]) + sizeof (MonoObject);
2091                                 break;
2092                         case MONO_TYPE_STRING:
2093                         case MONO_TYPE_OBJECT:
2094                         case MONO_TYPE_CLASS:
2095                         case MONO_TYPE_ARRAY:
2096                         case MONO_TYPE_SZARRAY:
2097                                 if (sig->params [i]->byref)
2098                                         pa [i] = &(((gpointer *)params->vector)[i]);
2099                                 else
2100                                         pa [i] = (char *)(((gpointer *)params->vector)[i]);
2101                                 break;
2102                         default:
2103                                 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
2104                         }
2105                 }
2106         }
2107
2108         if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
2109                 void *o = obj;
2110                 if (!obj) {
2111                         obj = mono_object_new (mono_domain_get (), method->klass);
2112                         if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
2113                                 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
2114                         }
2115                         if (method->klass->valuetype)
2116                                 o = mono_object_unbox (obj);
2117                         else
2118                                 o = obj;
2119                 }
2120                 else if (method->klass->valuetype)
2121                         obj = mono_value_box (mono_domain_get (), method->klass, obj);
2122
2123                 mono_runtime_invoke (method, o, pa, exc);
2124                 return obj;
2125         } else {
2126                 /* obj must be already unboxed if needed */
2127                 return mono_runtime_invoke (method, obj, pa, exc);
2128         }
2129 }
2130
2131 static void
2132 arith_overflow (void)
2133 {
2134         mono_raise_exception (mono_get_exception_overflow ());
2135 }
2136
2137 /**
2138  * mono_object_allocate:
2139  * @size: number of bytes to allocate
2140  *
2141  * This is a very simplistic routine until we have our GC-aware
2142  * memory allocator. 
2143  *
2144  * Returns: an allocated object of size @size, or NULL on failure.
2145  */
2146 static inline void *
2147 mono_object_allocate (size_t size, MonoVTable *vtable)
2148 {
2149         MonoObject *o;
2150         mono_stats.new_object_count++;
2151         ALLOC_OBJECT (o, vtable, size);
2152
2153         return o;
2154 }
2155
2156 /**
2157  * mono_object_allocate_ptrfree:
2158  * @size: number of bytes to allocate
2159  *
2160  * Note that the memory allocated is not zeroed.
2161  * Returns: an allocated object of size @size, or NULL on failure.
2162  */
2163 static inline void *
2164 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
2165 {
2166         MonoObject *o;
2167         mono_stats.new_object_count++;
2168         ALLOC_PTRFREE (o, vtable, size);
2169         return o;
2170 }
2171
2172 static inline void *
2173 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
2174 {
2175         void *o;
2176         ALLOC_TYPED (o, size, vtable);
2177         mono_stats.new_object_count++;
2178
2179         return o;
2180 }
2181
2182 /**
2183  * mono_object_new:
2184  * @klass: the class of the object that we want to create
2185  *
2186  * Returns: a newly created object whose definition is
2187  * looked up using @klass.   This will not invoke any constructors, 
2188  * so the consumer of this routine has to invoke any constructors on
2189  * its own to initialize the object.
2190  */
2191 MonoObject *
2192 mono_object_new (MonoDomain *domain, MonoClass *klass)
2193 {
2194         MONO_ARCH_SAVE_REGS;
2195         return mono_object_new_specific (mono_class_vtable (domain, klass));
2196 }
2197
2198 /**
2199  * mono_object_new_specific:
2200  * @vtable: the vtable of the object that we want to create
2201  *
2202  * Returns: A newly created object with class and domain specified
2203  * by @vtable
2204  */
2205 MonoObject *
2206 mono_object_new_specific (MonoVTable *vtable)
2207 {
2208         MonoObject *o;
2209
2210         MONO_ARCH_SAVE_REGS;
2211         
2212         if (vtable->remote)
2213         {
2214                 gpointer pa [1];
2215                 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
2216
2217                 if (im == NULL) {
2218                         MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
2219
2220                         if (!klass->inited)
2221                                 mono_class_init (klass);
2222
2223                         im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
2224                         g_assert (im);
2225                         vtable->domain->create_proxy_for_type_method = im;
2226                 }
2227         
2228                 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
2229
2230                 o = mono_runtime_invoke (im, NULL, pa, NULL);           
2231                 if (o != NULL) return o;
2232         }
2233
2234         return mono_object_new_alloc_specific (vtable);
2235 }
2236
2237 MonoObject *
2238 mono_object_new_alloc_specific (MonoVTable *vtable)
2239 {
2240         MonoObject *o;
2241
2242         if (!vtable->klass->has_references) {
2243                 o = mono_object_new_ptrfree (vtable);
2244         } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2245                 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
2246         } else {
2247 /*              printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
2248                 o = mono_object_allocate (vtable->klass->instance_size, vtable);
2249         }
2250         if (vtable->klass->has_finalize)
2251                 mono_object_register_finalizer (o);
2252         
2253         mono_profiler_allocation (o, vtable->klass);
2254         return o;
2255 }
2256
2257 MonoObject*
2258 mono_object_new_fast (MonoVTable *vtable)
2259 {
2260         MonoObject *o;
2261         ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
2262         return o;
2263 }
2264
2265 static MonoObject*
2266 mono_object_new_ptrfree (MonoVTable *vtable)
2267 {
2268         MonoObject *obj;
2269         ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
2270 #if NEED_TO_ZERO_PTRFREE
2271         /* an inline memset is much faster for the common vcase of small objects
2272          * note we assume the allocated size is a multiple of sizeof (void*).
2273          */
2274         if (vtable->klass->instance_size < 128) {
2275                 gpointer *p, *end;
2276                 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
2277                 p = (gpointer*)((char*)obj + sizeof (MonoObject));
2278                 while (p < end) {
2279                         *p = NULL;
2280                         ++p;
2281                 }
2282         } else {
2283                 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
2284         }
2285 #endif
2286         return obj;
2287 }
2288
2289 static MonoObject*
2290 mono_object_new_ptrfree_box (MonoVTable *vtable)
2291 {
2292         MonoObject *obj;
2293         ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
2294         /* the object will be boxed right away, no need to memzero it */
2295         return obj;
2296 }
2297
2298 /**
2299  * mono_class_get_allocation_ftn:
2300  * @vtable: vtable
2301  * @for_box: the object will be used for boxing
2302  * @pass_size_in_words: 
2303  *
2304  * Return the allocation function appropriate for the given class.
2305  */
2306
2307 void*
2308 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
2309 {
2310         *pass_size_in_words = FALSE;
2311
2312         if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
2313                 return mono_object_new_specific;
2314
2315         if (!vtable->klass->has_references) {
2316                 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
2317                 if (for_box)
2318                         return mono_object_new_ptrfree_box;
2319                 return mono_object_new_ptrfree;
2320         }
2321
2322         if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2323
2324                 return mono_object_new_fast;
2325
2326                 /* 
2327                  * FIXME: This is actually slower than mono_object_new_fast, because
2328                  * of the overhead of parameter passing.
2329                  */
2330                 /*
2331                 *pass_size_in_words = TRUE;
2332 #ifdef GC_REDIRECT_TO_LOCAL
2333                 return GC_local_gcj_fast_malloc;
2334 #else
2335                 return GC_gcj_fast_malloc;
2336 #endif
2337                 */
2338         }
2339
2340         return mono_object_new_specific;
2341 }
2342
2343 /**
2344  * mono_object_new_from_token:
2345  * @image: Context where the type_token is hosted
2346  * @token: a token of the type that we want to create
2347  *
2348  * Returns: A newly created object whose definition is
2349  * looked up using @token in the @image image
2350  */
2351 MonoObject *
2352 mono_object_new_from_token  (MonoDomain *domain, MonoImage *image, guint32 token)
2353 {
2354         MonoClass *class;
2355
2356         class = mono_class_get (image, token);
2357
2358         return mono_object_new (domain, class);
2359 }
2360
2361
2362 /**
2363  * mono_object_clone:
2364  * @obj: the object to clone
2365  *
2366  * Returns: A newly created object who is a shallow copy of @obj
2367  */
2368 MonoObject *
2369 mono_object_clone (MonoObject *obj)
2370 {
2371         MonoObject *o;
2372         int size;
2373
2374         size = obj->vtable->klass->instance_size;
2375         o = mono_object_allocate (size, obj->vtable);
2376         /* do not copy the sync state */
2377         memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
2378         
2379         mono_profiler_allocation (o, obj->vtable->klass);
2380
2381         if (obj->vtable->klass->has_finalize)
2382                 mono_object_register_finalizer (o);
2383         return o;
2384 }
2385
2386 /**
2387  * mono_array_full_copy:
2388  * @src: source array to copy
2389  * @dest: destination array
2390  *
2391  * Copies the content of one array to another with exactly the same type and size.
2392  */
2393 void
2394 mono_array_full_copy (MonoArray *src, MonoArray *dest)
2395 {
2396         int size;
2397         MonoClass *klass = src->obj.vtable->klass;
2398
2399         MONO_ARCH_SAVE_REGS;
2400
2401         g_assert (klass == dest->obj.vtable->klass);
2402
2403         size = mono_array_length (src);
2404         g_assert (size == mono_array_length (dest));
2405         size *= mono_array_element_size (klass);
2406         memcpy (&dest->vector, &src->vector, size);
2407 }
2408
2409 /**
2410  * mono_array_clone_in_domain:
2411  * @domain: the domain in which the array will be cloned into
2412  * @array: the array to clone
2413  *
2414  * This routine returns a copy of the array that is hosted on the
2415  * specified MonoDomain.
2416  */
2417 MonoArray*
2418 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
2419 {
2420         MonoArray *o;
2421         guint32 size, i;
2422         guint32 *sizes;
2423         MonoClass *klass = array->obj.vtable->klass;
2424
2425         MONO_ARCH_SAVE_REGS;
2426
2427         if (array->bounds == NULL) {
2428                 size = mono_array_length (array);
2429                 o = mono_array_new_full (domain, klass, &size, NULL);
2430
2431                 size *= mono_array_element_size (klass);
2432                 memcpy (&o->vector, &array->vector, size);
2433                 return o;
2434         }
2435         
2436         sizes = alloca (klass->rank * sizeof(guint32) * 2);
2437         size = mono_array_element_size (klass);
2438         for (i = 0; i < klass->rank; ++i) {
2439                 sizes [i] = array->bounds [i].length;
2440                 size *= array->bounds [i].length;
2441                 sizes [i + klass->rank] = array->bounds [i].lower_bound;
2442         }
2443         o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
2444         memcpy (&o->vector, &array->vector, size);
2445
2446         return o;
2447 }
2448
2449 /**
2450  * mono_array_clone:
2451  * @array: the array to clone
2452  *
2453  * Returns: A newly created array who is a shallow copy of @array
2454  */
2455 MonoArray*
2456 mono_array_clone (MonoArray *array)
2457 {
2458         return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
2459 }
2460
2461 /* helper macros to check for overflow when calculating the size of arrays */
2462 #define MYGUINT32_MAX 4294967295U
2463 #define CHECK_ADD_OVERFLOW_UN(a,b) \
2464         (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
2465 #define CHECK_MUL_OVERFLOW_UN(a,b) \
2466         ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
2467         (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
2468
2469 /**
2470  * mono_array_new_full:
2471  * @domain: domain where the object is created
2472  * @array_class: array class
2473  * @lengths: lengths for each dimension in the array
2474  * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
2475  *
2476  * This routine creates a new array objects with the given dimensions,
2477  * lower bounds and type.
2478  */
2479 MonoArray*
2480 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, 
2481                      guint32 *lengths, guint32 *lower_bounds)
2482 {
2483         guint32 byte_len, len, bounds_size;
2484         MonoObject *o;
2485         MonoArray *array;
2486         MonoVTable *vtable;
2487         int i;
2488
2489         if (!array_class->inited)
2490                 mono_class_init (array_class);
2491
2492         byte_len = mono_array_element_size (array_class);
2493         len = 1;
2494
2495         if (array_class->rank == 1 &&
2496             (lower_bounds == NULL || lower_bounds [0] == 0)) {
2497                 len = lengths [0];
2498                 if ((int) len < 0)
2499                         arith_overflow ();
2500                 bounds_size = 0;
2501         } else {
2502                 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
2503
2504                 for (i = 0; i < array_class->rank; ++i) {
2505                         if ((int) lengths [i] < 0)
2506                                 arith_overflow ();
2507                         if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
2508                                 mono_gc_out_of_memory (MYGUINT32_MAX);
2509                         len *= lengths [i];
2510                 }
2511         }
2512
2513         if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
2514                 mono_gc_out_of_memory (MYGUINT32_MAX);
2515         byte_len *= len;
2516         if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
2517                 mono_gc_out_of_memory (MYGUINT32_MAX);
2518         byte_len += sizeof (MonoArray);
2519         if (bounds_size) {
2520                 /* align */
2521                 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
2522                         mono_gc_out_of_memory (MYGUINT32_MAX);
2523                 byte_len = (byte_len + 3) & ~3;
2524                 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
2525                         mono_gc_out_of_memory (MYGUINT32_MAX);
2526                 byte_len += bounds_size;
2527         }
2528         /* 
2529          * Following three lines almost taken from mono_object_new ():
2530          * they need to be kept in sync.
2531          */
2532         vtable = mono_class_vtable (domain, array_class);
2533         if (!array_class->has_references) {
2534                 o = mono_object_allocate_ptrfree (byte_len, vtable);
2535 #if NEED_TO_ZERO_PTRFREE
2536                 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
2537 #endif
2538         } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2539                 o = mono_object_allocate_spec (byte_len, vtable);
2540         }else {
2541                 o = mono_object_allocate (byte_len, vtable);
2542         }
2543
2544         array = (MonoArray*)o;
2545         array->max_length = len;
2546
2547         if (bounds_size) {
2548                 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
2549                 array->bounds = bounds;
2550                 for (i = 0; i < array_class->rank; ++i) {
2551                         bounds [i].length = lengths [i];
2552                         if (lower_bounds)
2553                                 bounds [i].lower_bound = lower_bounds [i];
2554                 }
2555         }
2556
2557         mono_profiler_allocation (o, array_class);
2558
2559         return array;
2560 }
2561
2562 /**
2563  * mono_array_new:
2564  * @domain: domain where the object is created
2565  * @eclass: element class
2566  * @n: number of array elements
2567  *
2568  * This routine creates a new szarray with @n elements of type @eclass.
2569  */
2570 MonoArray *
2571 mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
2572 {
2573         MonoClass *ac;
2574
2575         MONO_ARCH_SAVE_REGS;
2576
2577         ac = mono_array_class_get (eclass, 1);
2578         g_assert (ac != NULL);
2579
2580         return mono_array_new_specific (mono_class_vtable (domain, ac), n);
2581 }
2582
2583 /**
2584  * mono_array_new_specific:
2585  * @vtable: a vtable in the appropriate domain for an initialized class
2586  * @n: number of array elements
2587  *
2588  * This routine is a fast alternative to mono_array_new() for code which
2589  * can be sure about the domain it operates in.
2590  */
2591 MonoArray *
2592 mono_array_new_specific (MonoVTable *vtable, guint32 n)
2593 {
2594         MonoObject *o;
2595         MonoArray *ao;
2596         guint32 byte_len, elem_size;
2597
2598         MONO_ARCH_SAVE_REGS;
2599
2600         if ((int) n < 0)
2601                 arith_overflow ();
2602         
2603         elem_size = mono_array_element_size (vtable->klass);
2604         if (CHECK_MUL_OVERFLOW_UN (n, elem_size))
2605                 mono_gc_out_of_memory (MYGUINT32_MAX);
2606         byte_len = n * elem_size;
2607         if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
2608                 mono_gc_out_of_memory (MYGUINT32_MAX);
2609         byte_len += sizeof (MonoArray);
2610         if (!vtable->klass->has_references) {
2611                 o = mono_object_allocate_ptrfree (byte_len, vtable);
2612 #if NEED_TO_ZERO_PTRFREE
2613                 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
2614 #endif
2615         } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2616                 o = mono_object_allocate_spec (byte_len, vtable);
2617         } else {
2618 /*              printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
2619                 o = mono_object_allocate (byte_len, vtable);
2620         }
2621
2622         ao = (MonoArray *)o;
2623         ao->bounds = NULL;
2624         ao->max_length = n;
2625         mono_profiler_allocation (o, vtable->klass);
2626
2627         return ao;
2628 }
2629
2630 /**
2631  * mono_string_new_utf16:
2632  * @text: a pointer to an utf16 string
2633  * @len: the length of the string
2634  *
2635  * Returns: A newly created string object which contains @text.
2636  */
2637 MonoString *
2638 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
2639 {
2640         MonoString *s;
2641         
2642         s = mono_string_new_size (domain, len);
2643         g_assert (s != NULL);
2644
2645         memcpy (mono_string_chars (s), text, len * 2);
2646
2647         return s;
2648 }
2649
2650 /**
2651  * mono_string_new_size:
2652  * @text: a pointer to an utf16 string
2653  * @len: the length of the string
2654  *
2655  * Returns: A newly created string object of @len
2656  */
2657 MonoString *
2658 mono_string_new_size (MonoDomain *domain, gint32 len)
2659 {
2660         MonoString *s;
2661         MonoVTable *vtable;
2662         size_t size = (sizeof (MonoString) + ((len + 1) * 2));
2663
2664         /* overflow ? can't fit it, can't allocate it! */
2665         if (len > size)
2666                 mono_gc_out_of_memory (-1);
2667
2668         vtable = mono_class_vtable (domain, mono_defaults.string_class);
2669
2670         s = mono_object_allocate_ptrfree (size, vtable);
2671
2672         s->length = len;
2673 #if NEED_TO_ZERO_PTRFREE
2674         s->chars [len] = 0;
2675 #endif
2676         mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
2677
2678         return s;
2679 }
2680
2681 /**
2682  * mono_string_new_len:
2683  * @text: a pointer to an utf8 string
2684  * @length: number of bytes in @text to consider
2685  *
2686  * Returns: A newly created string object which contains @text.
2687  */
2688 MonoString*
2689 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
2690 {
2691         GError *error = NULL;
2692         MonoString *o = NULL;
2693         guint16 *ut;
2694         glong items_written;
2695
2696         ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
2697
2698         if (!error)
2699                 o = mono_string_new_utf16 (domain, ut, items_written);
2700         else 
2701                 g_error_free (error);
2702
2703         g_free (ut);
2704
2705         return o;
2706 }
2707
2708 /**
2709  * mono_string_new:
2710  * @text: a pointer to an utf8 string
2711  *
2712  * Returns: A newly created string object which contains @text.
2713  */
2714 MonoString*
2715 mono_string_new (MonoDomain *domain, const char *text)
2716 {
2717         GError *error = NULL;
2718         MonoString *o = NULL;
2719         guint16 *ut;
2720         glong items_written;
2721         int l;
2722
2723         l = strlen (text);
2724         
2725         ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
2726
2727         if (!error)
2728                 o = mono_string_new_utf16 (domain, ut, items_written);
2729         else 
2730                 g_error_free (error);
2731
2732         g_free (ut);
2733
2734         return o;
2735 }
2736
2737 /**
2738  * mono_string_new_wrapper:
2739  * @text: pointer to utf8 characters.
2740  *
2741  * Helper function to create a string object from @text in the current domain.
2742  */
2743 MonoString*
2744 mono_string_new_wrapper (const char *text)
2745 {
2746         MonoDomain *domain = mono_domain_get ();
2747
2748         MONO_ARCH_SAVE_REGS;
2749
2750         if (text)
2751                 return mono_string_new (domain, text);
2752
2753         return NULL;
2754 }
2755
2756 /**
2757  * mono_value_box:
2758  * @class: the class of the value
2759  * @value: a pointer to the unboxed data
2760  *
2761  * Returns: A newly created object which contains @value.
2762  */
2763 MonoObject *
2764 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
2765 {
2766         MonoObject *res;
2767         int size;
2768         MonoVTable *vtable;
2769
2770         g_assert (class->valuetype);
2771
2772         vtable = mono_class_vtable (domain, class);
2773         size = mono_class_instance_size (class);
2774         res = mono_object_allocate (size, vtable);
2775         mono_profiler_allocation (res, class);
2776
2777         size = size - sizeof (MonoObject);
2778
2779 #if NO_UNALIGNED_ACCESS
2780         memcpy ((char *)res + sizeof (MonoObject), value, size);
2781 #else
2782         switch (size) {
2783         case 1:
2784                 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
2785                 break;
2786         case 2:
2787                 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
2788                 break;
2789         case 4:
2790                 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
2791                 break;
2792         case 8:
2793                 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
2794                 break;
2795         default:
2796                 memcpy ((char *)res + sizeof (MonoObject), value, size);
2797         }
2798 #endif
2799         if (class->has_finalize)
2800                 mono_object_register_finalizer (res);
2801         return res;
2802 }
2803
2804 /**
2805  * mono_object_get_domain:
2806  * @obj: object to query
2807  * 
2808  * Returns: the MonoDomain where the object is hosted
2809  */
2810 MonoDomain*
2811 mono_object_get_domain (MonoObject *obj)
2812 {
2813         return mono_object_domain (obj);
2814 }
2815
2816 /**
2817  * mono_object_get_class:
2818  * @obj: object to query
2819  * 
2820  * Returns: the MonOClass of the object.
2821  */
2822 MonoClass*
2823 mono_object_get_class (MonoObject *obj)
2824 {
2825         return mono_object_class (obj);
2826 }
2827 /**
2828  * mono_object_get_size:
2829  * @o: object to query
2830  * 
2831  * Returns: the size, in bytes, of @o
2832  */
2833 guint
2834 mono_object_get_size (MonoObject* o)
2835 {
2836         MonoClass* klass = mono_object_class (o);
2837         
2838         if (klass == mono_defaults.string_class)
2839                 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
2840         else if (klass->parent == mono_defaults.array_class)
2841                 return sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length ((MonoArray*) o);
2842         else
2843                 return mono_class_instance_size (klass);
2844 }
2845
2846 /**
2847  * mono_object_unbox:
2848  * @obj: object to unbox
2849  * 
2850  * Returns: a pointer to the start of the valuetype boxed in this
2851  * object.
2852  *
2853  * This method will assert if the object passed is not a valuetype.
2854  */
2855 gpointer
2856 mono_object_unbox (MonoObject *obj)
2857 {
2858         /* add assert for valuetypes? */
2859         g_assert (obj->vtable->klass->valuetype);
2860         return ((char*)obj) + sizeof (MonoObject);
2861 }
2862
2863 /**
2864  * mono_object_isinst:
2865  * @obj: an object
2866  * @klass: a pointer to a class 
2867  *
2868  * Returns: @obj if @obj is derived from @klass
2869  */
2870 MonoObject *
2871 mono_object_isinst (MonoObject *obj, MonoClass *klass)
2872 {
2873         if (!klass->inited)
2874                 mono_class_init (klass);
2875
2876         if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) 
2877                 return mono_object_isinst_mbyref (obj, klass);
2878
2879         if (!obj)
2880                 return NULL;
2881
2882         return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
2883 }
2884
2885 MonoObject *
2886 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
2887 {
2888         MonoVTable *vt;
2889
2890         if (!obj)
2891                 return NULL;
2892
2893         vt = obj->vtable;
2894         
2895         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2896                 if ((klass->interface_id <= vt->max_interface_id) &&
2897                     (vt->interface_offsets [klass->interface_id] != 0))
2898                         return obj;
2899         }
2900         else {
2901                 MonoClass *oklass = vt->klass;
2902                 if ((oklass == mono_defaults.transparent_proxy_class))
2903                         oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2904         
2905                 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
2906                         return obj;
2907         }
2908
2909         if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info) 
2910         {
2911                 MonoDomain *domain = mono_domain_get ();
2912                 MonoObject *res;
2913                 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
2914                 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
2915                 MonoMethod *im = NULL;
2916                 gpointer pa [2];
2917
2918                 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
2919                 im = mono_object_get_virtual_method (rp, im);
2920                 g_assert (im);
2921         
2922                 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
2923                 pa [1] = obj;
2924
2925                 res = mono_runtime_invoke (im, rp, pa, NULL);
2926         
2927                 if (*(MonoBoolean *) mono_object_unbox(res)) {
2928                         /* Update the vtable of the remote type, so it can safely cast to this new type */
2929                         mono_upgrade_remote_class (domain, obj, klass);
2930                         return obj;
2931                 }
2932         }
2933
2934         return NULL;
2935 }
2936
2937 /**
2938  * mono_object_castclass_mbyref:
2939  * @obj: an object
2940  * @klass: a pointer to a class 
2941  *
2942  * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
2943  */
2944 MonoObject *
2945 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
2946 {
2947         if (!obj) return NULL;
2948         if (mono_object_isinst_mbyref (obj, klass)) return obj;
2949                 
2950         mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
2951                                                         "System",
2952                                                         "InvalidCastException"));
2953         return NULL;
2954 }
2955
2956 typedef struct {
2957         MonoDomain *orig_domain;
2958         MonoString *ins;
2959         MonoString *res;
2960 } LDStrInfo;
2961
2962 static void
2963 str_lookup (MonoDomain *domain, gpointer user_data)
2964 {
2965         LDStrInfo *info = user_data;
2966         if (info->res || domain == info->orig_domain)
2967                 return;
2968         mono_domain_lock (domain);
2969         info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
2970         mono_domain_unlock (domain);
2971 }
2972
2973 static MonoString*
2974 mono_string_is_interned_lookup (MonoString *str, int insert)
2975 {
2976         MonoGHashTable *ldstr_table;
2977         MonoString *res;
2978         MonoDomain *domain;
2979         
2980         domain = ((MonoObject *)str)->vtable->domain;
2981         ldstr_table = domain->ldstr_table;
2982         mono_domain_lock (domain);
2983         if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
2984                 mono_domain_unlock (domain);
2985                 return res;
2986         }
2987         if (insert) {
2988                 mono_g_hash_table_insert (ldstr_table, str, str);
2989                 mono_domain_unlock (domain);
2990                 return str;
2991         } else {
2992                 LDStrInfo ldstr_info;
2993                 ldstr_info.orig_domain = domain;
2994                 ldstr_info.ins = str;
2995                 ldstr_info.res = NULL;
2996
2997                 mono_domain_foreach (str_lookup, &ldstr_info);
2998                 if (ldstr_info.res) {
2999                         /* 
3000                          * the string was already interned in some other domain:
3001                          * intern it in the current one as well.
3002                          */
3003                         mono_g_hash_table_insert (ldstr_table, str, str);
3004                         mono_domain_unlock (domain);
3005                         return str;
3006                 }
3007         }
3008         mono_domain_unlock (domain);
3009         return NULL;
3010 }
3011
3012 /**
3013  * mono_string_is_interned:
3014  * @o: String to probe
3015  *
3016  * Returns whether the string has been interned.
3017  */
3018 MonoString*
3019 mono_string_is_interned (MonoString *o)
3020 {
3021         return mono_string_is_interned_lookup (o, FALSE);
3022 }
3023
3024 /**
3025  * mono_string_interne:
3026  * @o: String to intern
3027  *
3028  * Interns the string passed.  
3029  * Returns: The interned string.
3030  */
3031 MonoString*
3032 mono_string_intern (MonoString *str)
3033 {
3034         return mono_string_is_interned_lookup (str, TRUE);
3035 }
3036
3037 /**
3038  * mono_ldstr:
3039  * @domain: the domain where the string will be used.
3040  * @image: a metadata context
3041  * @idx: index into the user string table.
3042  * 
3043  * Implementation for the ldstr opcode.
3044  * Returns: a loaded string from the @image/@idx combination.
3045  */
3046 MonoString*
3047 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
3048 {
3049         MONO_ARCH_SAVE_REGS;
3050
3051         if (image->dynamic)
3052                 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx);
3053         else
3054                 return mono_ldstr_metdata_sig (domain, mono_metadata_user_string (image, idx));
3055 }
3056
3057 /**
3058  * mono_ldstr_metdata_sig
3059  * @domain: the domain for the string
3060  * @sig: the signature of a metadata string
3061  *
3062  * Returns: a MonoString for a string stored in the metadata
3063  */
3064 static MonoString*
3065 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig)
3066 {
3067         const char *str = sig;
3068         MonoString *o, *interned;
3069         size_t len2;
3070         
3071         len2 = mono_metadata_decode_blob_size (str, &str);
3072         len2 >>= 1;
3073
3074         o = mono_string_new_utf16 (domain, (guint16*)str, len2);
3075 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
3076         {
3077                 int i;
3078                 guint16 *p2 = (guint16*)mono_string_chars (o);
3079                 for (i = 0; i < len2; ++i) {
3080                         *p2 = GUINT16_FROM_LE (*p2);
3081                         ++p2;
3082                 }
3083         }
3084 #endif
3085         mono_domain_lock (domain);
3086         if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
3087                 mono_domain_unlock (domain);
3088                 /* o will get garbage collected */
3089                 return interned;
3090         }
3091
3092         mono_g_hash_table_insert (domain->ldstr_table, o, o);
3093         mono_domain_unlock (domain);
3094
3095         return o;
3096 }
3097
3098 /**
3099  * mono_string_to_utf8:
3100  * @s: a System.String
3101  *
3102  * Return the UTF8 representation for @s.
3103  * the resulting buffer nedds to be freed with g_free().
3104  */
3105 char *
3106 mono_string_to_utf8 (MonoString *s)
3107 {
3108         char *as;
3109         GError *error = NULL;
3110
3111         if (s == NULL)
3112                 return NULL;
3113
3114         if (!s->length)
3115                 return g_strdup ("");
3116
3117         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, NULL, &error);
3118         if (error) {
3119                 g_warning (error->message);
3120                 g_error_free (error);
3121         }
3122
3123         return as;
3124 }
3125
3126 /**
3127  * mono_string_to_utf16:
3128  * @s: a MonoString
3129  *
3130  * Return an null-terminated array of the utf-16 chars
3131  * contained in @s. The result must be freed with g_free().
3132  * This is a temporary helper until our string implementation
3133  * is reworked to always include the null terminating char.
3134  */
3135 gunichar2 *
3136 mono_string_to_utf16 (MonoString *s)
3137 {
3138         char *as;
3139
3140         if (s == NULL)
3141                 return NULL;
3142
3143         as = g_malloc ((s->length * 2) + 2);
3144         as [(s->length * 2)] = '\0';
3145         as [(s->length * 2) + 1] = '\0';
3146
3147         if (!s->length) {
3148                 return (gunichar2 *)(as);
3149         }
3150         
3151         memcpy (as, mono_string_chars(s), s->length * 2);
3152         return (gunichar2 *)(as);
3153 }
3154
3155 /**
3156  * mono_string_from_utf16:
3157  * @data: the UTF16 string (LPWSTR) to convert
3158  *
3159  * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
3160  *
3161  * Returns: a MonoString.
3162  */
3163 MonoString *
3164 mono_string_from_utf16 (gunichar2 *data)
3165 {
3166         MonoDomain *domain = mono_domain_get ();
3167         int len = 0;
3168
3169         if (!data)
3170                 return NULL;
3171
3172         while (data [len]) len++;
3173
3174         return mono_string_new_utf16 (domain, data, len);
3175 }
3176
3177 static void
3178 default_ex_handler (MonoException *ex)
3179 {
3180         MonoObject *o = (MonoObject*)ex;
3181         g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
3182         exit (1);
3183 }
3184
3185 static MonoExceptionFunc ex_handler = default_ex_handler;
3186
3187 /**
3188  * mono_install_handler:
3189  * @func: exception handler
3190  *
3191  * This is an internal JIT routine used to install the handler for exceptions
3192  * being throwh.
3193  */
3194 void
3195 mono_install_handler (MonoExceptionFunc func)
3196 {
3197         ex_handler = func? func: default_ex_handler;
3198 }
3199
3200 /**
3201  * mono_raise_exception:
3202  * @ex: exception object
3203  *
3204  * Signal the runtime that the exception @ex has been raised in unmanaged code.
3205  */
3206 void
3207 mono_raise_exception (MonoException *ex) 
3208 {
3209         /*
3210          * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
3211          * that will cause gcc to omit the function epilog, causing problems when
3212          * the JIT tries to walk the stack, since the return address on the stack
3213          * will point into the next function in the executable, not this one.
3214          */
3215
3216         if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class)
3217                 mono_thread_current ()->abort_exc = ex;
3218         
3219         ex_handler (ex);
3220 }
3221
3222 /**
3223  * mono_wait_handle_new:
3224  * @domain: Domain where the object will be created
3225  * @handle: Handle for the wait handle
3226  *
3227  * Returns: A new MonoWaitHandle created in the given domain for the given handle
3228  */
3229 MonoWaitHandle *
3230 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
3231 {
3232         MonoWaitHandle *res;
3233
3234         res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
3235
3236         res->handle = handle;
3237
3238         return res;
3239 }
3240
3241 /**
3242  * mono_async_result_new:
3243  * @domain:domain where the object will be created.
3244  * @handle: wait handle.
3245  * @state: state to pass to AsyncResult
3246  * @data: C closure data.
3247  *
3248  * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
3249  * If the handle is not null, the handle is initialized to a MonOWaitHandle.
3250  *
3251  */
3252 MonoAsyncResult *
3253 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data)
3254 {
3255         MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
3256         MonoMethod *method = mono_get_context_capture_method ();
3257
3258         /* we must capture the execution context from the original thread */
3259         if (method) {
3260                 res->execution_context = mono_runtime_invoke (method, NULL, NULL, NULL);
3261                 /* note: result may be null if the flow is suppressed */
3262         }
3263
3264         res->data = data;
3265         res->async_state = state;
3266         if (handle != NULL)
3267                 res->handle = (MonoObject *) mono_wait_handle_new (domain, handle);
3268
3269         res->sync_completed = FALSE;
3270         res->completed = FALSE;
3271
3272         return res;
3273 }
3274
3275 void
3276 mono_message_init (MonoDomain *domain,
3277                    MonoMethodMessage *this, 
3278                    MonoReflectionMethod *method,
3279                    MonoArray *out_args)
3280 {
3281         MonoMethodSignature *sig = mono_method_signature (method->method);
3282         MonoString *name;
3283         int i, j;
3284         char **names;
3285         guint8 arg_type;
3286
3287         this->method = method;
3288
3289         this->args = mono_array_new (domain, mono_defaults.object_class, sig->param_count);
3290         this->arg_types = mono_array_new (domain, mono_defaults.byte_class, sig->param_count);
3291         this->async_result = NULL;
3292         this->call_type = CallType_Sync;
3293
3294         names = g_new (char *, sig->param_count);
3295         mono_method_get_param_names (method->method, (const char **) names);
3296         this->names = mono_array_new (domain, mono_defaults.string_class, sig->param_count);
3297         
3298         for (i = 0; i < sig->param_count; i++) {
3299                  name = mono_string_new (domain, names [i]);
3300                  mono_array_set (this->names, gpointer, i, name);       
3301         }
3302
3303         g_free (names);
3304         for (i = 0, j = 0; i < sig->param_count; i++) {
3305
3306                 if (sig->params [i]->byref) {
3307                         if (out_args) {
3308                                 gpointer arg = mono_array_get (out_args, gpointer, j);
3309                                 mono_array_set (this->args, gpointer, i, arg);
3310                                 j++;
3311                         }
3312                         arg_type = 2;
3313                         if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
3314                                 arg_type |= 1;
3315                 } else {
3316                         arg_type = 1;
3317                 }
3318                 mono_array_set (this->arg_types, guint8, i, arg_type);
3319         }
3320 }
3321
3322 /**
3323  * mono_remoting_invoke:
3324  * @real_proxy: pointer to a RealProxy object
3325  * @msg: The MonoMethodMessage to execute
3326  * @exc: used to store exceptions
3327  * @out_args: used to store output arguments
3328  *
3329  * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
3330  * IMessage interface and it is not trivial to extract results from there. So
3331  * we call an helper method PrivateInvoke instead of calling
3332  * RealProxy::Invoke() directly.
3333  *
3334  * Returns: the result object.
3335  */
3336 MonoObject *
3337 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, 
3338                       MonoObject **exc, MonoArray **out_args)
3339 {
3340         MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
3341         gpointer pa [4];
3342
3343         /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
3344
3345         if (!im) {
3346                 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
3347                 g_assert (im);
3348                 real_proxy->vtable->domain->private_invoke_method = im;
3349         }
3350
3351         pa [0] = real_proxy;
3352         pa [1] = msg;
3353         pa [2] = exc;
3354         pa [3] = out_args;
3355
3356         return mono_runtime_invoke (im, NULL, pa, exc);
3357 }
3358
3359 MonoObject *
3360 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
3361                      MonoObject **exc, MonoArray **out_args) 
3362 {
3363         MonoDomain *domain; 
3364         MonoMethod *method;
3365         MonoMethodSignature *sig;
3366         MonoObject *ret;
3367         int i, j, outarg_count = 0;
3368
3369         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
3370
3371                 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
3372                 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3373                         target = tp->rp->unwrapped_server;
3374                 } else {
3375                         return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
3376                 }
3377         }
3378
3379         domain = mono_domain_get (); 
3380         method = msg->method->method;
3381         sig = mono_method_signature (method);
3382
3383         for (i = 0; i < sig->param_count; i++) {
3384                 if (sig->params [i]->byref) 
3385                         outarg_count++;
3386         }
3387
3388         *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
3389         *exc = NULL;
3390
3391         ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
3392
3393         for (i = 0, j = 0; i < sig->param_count; i++) {
3394                 if (sig->params [i]->byref) {
3395                         gpointer arg;
3396                         arg = mono_array_get (msg->args, gpointer, i);
3397                         mono_array_set (*out_args, gpointer, j, arg);
3398                         j++;
3399                 }
3400         }
3401
3402         return ret;
3403 }
3404
3405 /**
3406  * mono_print_unhandled_exception:
3407  * @exc: The exception
3408  *
3409  * Prints the unhandled exception.
3410  */
3411 void
3412 mono_print_unhandled_exception (MonoObject *exc)
3413 {
3414         char *message = (char *) "";
3415         MonoString *str; 
3416         MonoMethod *method;
3417         MonoClass *klass;
3418         gboolean free_message = FALSE;
3419
3420         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
3421                 klass = exc->vtable->klass;
3422                 method = NULL;
3423                 while (klass && method == NULL) {
3424                         method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
3425                         if (method == NULL)
3426                                 klass = klass->parent;
3427                 }
3428
3429                 g_assert (method);
3430
3431                 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
3432                 if (str) {
3433                         message = mono_string_to_utf8 (str);
3434                         free_message = TRUE;
3435                 }
3436         }                               
3437
3438         /*
3439          * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space, 
3440          *         exc->vtable->klass->name, message);
3441          */
3442         g_printerr ("\nUnhandled Exception: %s\n", message);
3443         
3444         if (free_message)
3445                 g_free (message);
3446 }
3447
3448 /**
3449  * mono_delegate_ctor:
3450  * @this: pointer to an uninitialized delegate object
3451  * @target: target object
3452  * @addr: pointer to native code
3453  *
3454  * This is used to initialize a delegate. We also insert the method_info if
3455  * we find the info with mono_jit_info_table_find().
3456  */
3457 void
3458 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
3459 {
3460         MonoDomain *domain = mono_domain_get ();
3461         MonoDelegate *delegate = (MonoDelegate *)this;
3462         MonoMethod *method = NULL;
3463         MonoClass *class;
3464         MonoJitInfo *ji;
3465
3466         g_assert (this);
3467         g_assert (addr);
3468
3469         class = this->vtable->klass;
3470
3471         if ((ji = mono_jit_info_table_find (domain, addr))) {
3472                 method = ji->method;
3473                 delegate->method_info = mono_method_get_object (domain, method, NULL);
3474         }
3475
3476         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
3477                 g_assert (method);
3478                 method = mono_marshal_get_remoting_invoke (method);
3479                 delegate->method_ptr = mono_compile_method (method);
3480                 delegate->target = target;
3481         } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
3482                 method = mono_marshal_get_unbox_wrapper (method);
3483                 delegate->method_ptr = mono_compile_method (method);
3484                 delegate->target = target;
3485         } else {
3486                 delegate->method_ptr = addr;
3487                 delegate->target = target;
3488         }
3489 }
3490
3491 /**
3492  * mono_method_call_message_new:
3493  * @method: method to encapsulate
3494  * @params: parameters to the method
3495  * @invoke: optional, delegate invoke.
3496  * @cb: async callback delegate.
3497  * @state: state passed to the async callback.
3498  *
3499  * Translates arguments pointers into a MonoMethodMessage.
3500  */
3501 MonoMethodMessage *
3502 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke, 
3503                               MonoDelegate **cb, MonoObject **state)
3504 {
3505         MonoDomain *domain = mono_domain_get ();
3506         MonoMethodSignature *sig = mono_method_signature (method);
3507         MonoMethodMessage *msg;
3508         int i, count, type;
3509
3510         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class); 
3511         
3512         if (invoke) {
3513                 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
3514                 count =  sig->param_count - 2;
3515         } else {
3516                 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
3517                 count =  sig->param_count;
3518         }
3519
3520         for (i = 0; i < count; i++) {
3521                 gpointer vpos;
3522                 MonoClass *class;
3523                 MonoObject *arg;
3524
3525                 if (sig->params [i]->byref)
3526                         vpos = *((gpointer *)params [i]);
3527                 else 
3528                         vpos = params [i];
3529
3530                 type = sig->params [i]->type;
3531                 class = mono_class_from_mono_type (sig->params [i]);
3532
3533                 if (class->valuetype)
3534                         arg = mono_value_box (domain, class, vpos);
3535                 else 
3536                         arg = *((MonoObject **)vpos);
3537                       
3538                 mono_array_set (msg->args, gpointer, i, arg);
3539         }
3540
3541         if (cb != NULL && state != NULL) {
3542                 *cb = *((MonoDelegate **)params [i]);
3543                 i++;
3544                 *state = *((MonoObject **)params [i]);
3545         }
3546
3547         return msg;
3548 }
3549
3550 /**
3551  * mono_method_return_message_restore:
3552  *
3553  * Restore results from message based processing back to arguments pointers
3554  */
3555 void
3556 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
3557 {
3558         MonoMethodSignature *sig = mono_method_signature (method);
3559         int i, j, type, size, out_len;
3560         
3561         if (out_args == NULL)
3562                 return;
3563         out_len = mono_array_length (out_args);
3564         if (out_len == 0)
3565                 return;
3566
3567         for (i = 0, j = 0; i < sig->param_count; i++) {
3568                 MonoType *pt = sig->params [i];
3569
3570                 if (pt->byref) {
3571                         char *arg;
3572                         if (j >= out_len)
3573                                 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
3574
3575                         arg = mono_array_get (out_args, gpointer, j);
3576                         type = pt->type;
3577
3578                         switch (type) {
3579                         case MONO_TYPE_VOID:
3580                                 g_assert_not_reached ();
3581                                 break;
3582                         case MONO_TYPE_U1:
3583                         case MONO_TYPE_I1:
3584                         case MONO_TYPE_BOOLEAN:
3585                         case MONO_TYPE_U2:
3586                         case MONO_TYPE_I2:
3587                         case MONO_TYPE_CHAR:
3588                         case MONO_TYPE_U4:
3589                         case MONO_TYPE_I4:
3590                         case MONO_TYPE_I8:
3591                         case MONO_TYPE_U8:
3592                         case MONO_TYPE_R4:
3593                         case MONO_TYPE_R8:
3594                         case MONO_TYPE_VALUETYPE: {
3595                                 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
3596                                 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size); 
3597                                 break;
3598                         }
3599                         case MONO_TYPE_STRING:
3600                         case MONO_TYPE_CLASS: 
3601                         case MONO_TYPE_ARRAY:
3602                         case MONO_TYPE_SZARRAY:
3603                         case MONO_TYPE_OBJECT:
3604                                 **((MonoObject ***)params [i]) = (MonoObject *)arg;
3605                                 break;
3606                         default:
3607                                 g_assert_not_reached ();
3608                         }
3609
3610                         j++;
3611                 }
3612         }
3613 }
3614
3615 /**
3616  * mono_load_remote_field:
3617  * @this: pointer to an object
3618  * @klass: klass of the object containing @field
3619  * @field: the field to load
3620  * @res: a storage to store the result
3621  *
3622  * This method is called by the runtime on attempts to load fields of
3623  * transparent proxy objects. @this points to such TP, @klass is the class of
3624  * the object containing @field. @res is a storage location which can be
3625  * used to store the result.
3626  *
3627  * Returns: an address pointing to the value of field.
3628  */
3629 gpointer
3630 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
3631 {
3632         static MonoMethod *getter = NULL;
3633         MonoDomain *domain = mono_domain_get ();
3634         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3635         MonoClass *field_class;
3636         MonoMethodMessage *msg;
3637         MonoArray *out_args;
3638         MonoObject *exc;
3639         gpointer tmp;
3640
3641         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3642
3643         if (!res)
3644                 res = &tmp;
3645
3646         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3647                 mono_field_get_value (tp->rp->unwrapped_server, field, res);
3648                 return res;
3649         }
3650         
3651         if (!getter) {
3652                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
3653                 g_assert (getter);
3654         }
3655         
3656         field_class = mono_class_from_mono_type (field->type);
3657
3658         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3659         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
3660         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
3661
3662         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3663         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3664
3665         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3666
3667         if (exc) mono_raise_exception ((MonoException *)exc);
3668
3669         if (mono_array_length (out_args) == 0)
3670                 return NULL;
3671
3672         *res = mono_array_get (out_args, MonoObject *, 0);
3673
3674         if (field_class->valuetype) {
3675                 return ((char *)*res) + sizeof (MonoObject);
3676         } else
3677                 return res;
3678 }
3679
3680 /**
3681  * mono_load_remote_field_new:
3682  * @this: 
3683  * @klass: 
3684  * @field:
3685  *
3686  * Missing documentation.
3687  */
3688 MonoObject *
3689 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
3690 {
3691         static MonoMethod *getter = NULL;
3692         MonoDomain *domain = mono_domain_get ();
3693         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3694         MonoClass *field_class;
3695         MonoMethodMessage *msg;
3696         MonoArray *out_args;
3697         MonoObject *exc, *res;
3698
3699         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3700
3701         field_class = mono_class_from_mono_type (field->type);
3702
3703         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3704                 gpointer val;
3705                 if (field_class->valuetype) {
3706                         res = mono_object_new (domain, field_class);
3707                         val = ((gchar *) res) + sizeof (MonoObject);
3708                 } else {
3709                         val = &res;
3710                 }
3711                 mono_field_get_value (tp->rp->unwrapped_server, field, val);
3712                 return res;
3713         }
3714
3715         if (!getter) {
3716                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
3717                 g_assert (getter);
3718         }
3719         
3720         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3721         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
3722
3723         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
3724
3725         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3726         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3727
3728         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3729
3730         if (exc) mono_raise_exception ((MonoException *)exc);
3731
3732         if (mono_array_length (out_args) == 0)
3733                 res = NULL;
3734         else
3735                 res = mono_array_get (out_args, MonoObject *, 0);
3736
3737         return res;
3738 }
3739
3740 /**
3741  * mono_store_remote_field:
3742  * @this: pointer to an object
3743  * @klass: klass of the object containing @field
3744  * @field: the field to load
3745  * @val: the value/object to store
3746  *
3747  * This method is called by the runtime on attempts to store fields of
3748  * transparent proxy objects. @this points to such TP, @klass is the class of
3749  * the object containing @field. @val is the new value to store in @field.
3750  */
3751 void
3752 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
3753 {
3754         static MonoMethod *setter = NULL;
3755         MonoDomain *domain = mono_domain_get ();
3756         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3757         MonoClass *field_class;
3758         MonoMethodMessage *msg;
3759         MonoArray *out_args;
3760         MonoObject *exc;
3761         MonoObject *arg;
3762
3763         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3764
3765         field_class = mono_class_from_mono_type (field->type);
3766
3767         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3768                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
3769                 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
3770                 return;
3771         }
3772
3773         if (!setter) {
3774                 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
3775                 g_assert (setter);
3776         }
3777
3778         if (field_class->valuetype)
3779                 arg = mono_value_box (domain, field_class, val);
3780         else 
3781                 arg = *((MonoObject **)val);
3782                 
3783
3784         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3785         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
3786
3787         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3788         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3789         mono_array_set (msg->args, gpointer, 2, arg);
3790
3791         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3792
3793         if (exc) mono_raise_exception ((MonoException *)exc);
3794 }
3795
3796 /**
3797  * mono_store_remote_field_new:
3798  * @this:
3799  * @klass:
3800  * @field:
3801  * @arg:
3802  *
3803  * Missing documentation
3804  */
3805 void
3806 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
3807 {
3808         static MonoMethod *setter = NULL;
3809         MonoDomain *domain = mono_domain_get ();
3810         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3811         MonoClass *field_class;
3812         MonoMethodMessage *msg;
3813         MonoArray *out_args;
3814         MonoObject *exc;
3815
3816         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3817
3818         field_class = mono_class_from_mono_type (field->type);
3819
3820         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3821                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
3822                 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
3823                 return;
3824         }
3825
3826         if (!setter) {
3827                 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
3828                 g_assert (setter);
3829         }
3830
3831         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3832         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
3833
3834         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3835         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3836         mono_array_set (msg->args, gpointer, 2, arg);
3837
3838         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3839
3840         if (exc) mono_raise_exception ((MonoException *)exc);
3841 }
3842