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