Tue Aug 3 17:54:17 CEST 2004 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / metadata / object.c
1 /*
2  * object.c: Object creation for the Mono runtime
3  *
4  * Author:
5  *   Miguel de Icaza (miguel@ximian.com)
6  *   Paolo Molaro (lupus@ximian.com)
7  *
8  * (C) 2001-2004 Ximian, Inc.
9  */
10 #include <config.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <signal.h>
14 #include <string.h>
15 #include <mono/metadata/mono-endian.h>
16 #include <mono/metadata/tabledefs.h>
17 #include <mono/metadata/tokentype.h>
18 #include <mono/metadata/loader.h>
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/gc-internal.h>
21 #include <mono/metadata/exception.h>
22 #include <mono/metadata/domain-internals.h>
23 #include "mono/metadata/metadata-internals.h"
24 #include "mono/metadata/class-internals.h"
25 #include <mono/metadata/assembly.h>
26 #include <mono/metadata/threadpool.h>
27 #include <mono/metadata/marshal.h>
28 #include "mono/metadata/debug-helpers.h"
29 #include "mono/metadata/marshal.h"
30 #include <mono/metadata/threads.h>
31 #include <mono/metadata/threads-types.h>
32 #include <mono/metadata/environment.h>
33 #include "mono/metadata/profiler-private.h"
34 #include <mono/os/gc_wrapper.h>
35 #include <mono/utils/strenc.h>
36
37 /*
38  * Enable experimental typed allocation using the GC_gcj_malloc function.
39  */
40 #ifdef HAVE_GC_GCJ_MALLOC
41 #define CREATION_SPEEDUP 1
42 #endif
43
44 static void
45 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
46
47 static MonoString*
48 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig);
49
50 void
51 mono_runtime_object_init (MonoObject *this)
52 {
53         int i;
54         MonoMethod *method = NULL;
55         MonoClass *klass = this->vtable->klass;
56
57         for (i = 0; i < klass->method.count; ++i) {
58                 if (!strcmp (".ctor", klass->methods [i]->name) &&
59                     klass->methods [i]->signature->param_count == 0) {
60                         method = klass->methods [i];
61                         break;
62                 }
63         }
64
65         g_assert (method);
66
67         if (method->klass->valuetype)
68                 this = mono_object_unbox (this);
69         mono_runtime_invoke (method, this, NULL, NULL);
70 }
71
72 /* The pseudo algorithm for type initialization from the spec
73 Note it doesn't say anything about domains - only threads.
74
75 2. If the type is initialized you are done.
76 2.1. If the type is not yet initialized, try to take an 
77      initialization lock.  
78 2.2. If successful, record this thread as responsible for 
79      initializing the type and proceed to step 2.3.
80 2.2.1. If not, see whether this thread or any thread 
81      waiting for this thread to complete already holds the lock.
82 2.2.2. If so, return since blocking would create a deadlock.  This thread 
83      will now see an incompletely initialized state for the type, 
84      but no deadlock will arise.
85 2.2.3  If not, block until the type is initialized then return.
86 2.3 Initialize the parent type and then all interfaces implemented 
87     by this type.
88 2.4 Execute the type initialization code for this type.
89 2.5 Mark the type as initialized, release the initialization lock, 
90     awaken any threads waiting for this type to be initialized, 
91     and return.
92
93 */
94
95 typedef struct
96 {
97         guint32 initializing_tid;
98         guint32 waiting_count;
99         CRITICAL_SECTION initialization_section;
100 } TypeInitializationLock;
101
102 /* for locking access to type_initialization_hash and blocked_thread_hash */
103 static CRITICAL_SECTION type_initialization_section;
104
105 /* from vtable to lock */
106 static GHashTable *type_initialization_hash;
107
108 /* from thread id to thread id being waited on */
109 static GHashTable *blocked_thread_hash;
110
111 /* Main thread */
112 static MonoThread *main_thread;
113
114 void
115 mono_type_initialization_init (void)
116 {
117         InitializeCriticalSection (&type_initialization_section);
118         type_initialization_hash = g_hash_table_new (NULL, NULL);
119         blocked_thread_hash = g_hash_table_new (NULL, NULL);
120 }
121
122 /*
123  * mono_runtime_class_init:
124  * @vtable: vtable that needs to be initialized
125  *
126  * This routine calls the class constructor for @vtable.
127  */
128 void
129 mono_runtime_class_init (MonoVTable *vtable)
130 {
131         int i;
132         MonoException *exc;
133         MonoException *exc_to_throw;
134         MonoMethod *method = NULL;
135         MonoClass *klass;
136         gchar *full_name;
137         gboolean found;
138
139         MONO_ARCH_SAVE_REGS;
140
141         if (vtable->initialized)
142                 return;
143
144         exc = NULL;
145         found = FALSE;
146         klass = vtable->klass;
147
148         for (i = 0; i < klass->method.count; ++i) {
149                 method = klass->methods [i];
150                 if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && 
151                     (strcmp (".cctor", method->name) == 0)) {
152                         found = TRUE;
153                         break;
154                 }
155         }
156
157         if (found) {
158                 MonoDomain *domain = vtable->domain;
159                 TypeInitializationLock *lock;
160                 guint32 tid = GetCurrentThreadId();
161                 int do_initialization = 0;
162                 MonoDomain *last_domain = NULL;
163
164                 EnterCriticalSection (&type_initialization_section);
165                 /* double check... */
166                 if (vtable->initialized) {
167                         LeaveCriticalSection (&type_initialization_section);
168                         return;
169                 }
170                 lock = g_hash_table_lookup (type_initialization_hash, vtable);
171                 if (lock == NULL) {
172                         /* This thread will get to do the initialization */
173                         if (mono_domain_get () != domain) {
174                                 /* Transfer into the target domain */
175                                 last_domain = mono_domain_get ();
176                                 if (!mono_domain_set (domain, FALSE)) {
177                                         vtable->initialized = 1;
178                                         LeaveCriticalSection (&type_initialization_section);
179                                         mono_raise_exception (mono_get_exception_appdomain_unloaded ());
180                                 }
181                         }
182                         lock = g_malloc (sizeof(TypeInitializationLock));
183                         InitializeCriticalSection (&lock->initialization_section);
184                         lock->initializing_tid = tid;
185                         lock->waiting_count = 1;
186                         /* grab the vtable lock while this thread still owns type_initialization_section */
187                         EnterCriticalSection (&lock->initialization_section);
188                         g_hash_table_insert (type_initialization_hash, vtable, lock);
189                         do_initialization = 1;
190                 } else {
191                         gpointer blocked;
192
193                         if (lock->initializing_tid == tid) {
194                                 LeaveCriticalSection (&type_initialization_section);
195                                 return;
196                         }
197                         /* see if the thread doing the initialization is already blocked on this thread */
198                         blocked = GUINT_TO_POINTER (lock->initializing_tid);
199                         while ((blocked = g_hash_table_lookup (blocked_thread_hash, blocked))) {
200                                 if (blocked == GUINT_TO_POINTER (tid)) {
201                                         LeaveCriticalSection (&type_initialization_section);
202                                         return;
203                                 }
204                         }
205                         ++lock->waiting_count;
206                         /* record the fact that we are waiting on the initializing thread */
207                         g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), GUINT_TO_POINTER (lock->initializing_tid));
208                 }
209                 LeaveCriticalSection (&type_initialization_section);
210
211                 if (do_initialization) {
212                         mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
213                         if (last_domain)
214                                 mono_domain_set (last_domain, TRUE);
215                         LeaveCriticalSection (&lock->initialization_section);
216                 } else {
217                         /* this just blocks until the initializing thread is done */
218                         EnterCriticalSection (&lock->initialization_section);
219                         LeaveCriticalSection (&lock->initialization_section);
220                 }
221
222                 EnterCriticalSection (&type_initialization_section);
223                 if (lock->initializing_tid != tid)
224                         g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
225                 --lock->waiting_count;
226                 if (lock->waiting_count == 0) {
227                         DeleteCriticalSection (&lock->initialization_section);
228                         g_hash_table_remove (type_initialization_hash, vtable);
229                         g_free (lock);
230                 }
231                 vtable->initialized = 1;
232                 /* FIXME: if the cctor fails, the type must be marked as unusable */
233                 LeaveCriticalSection (&type_initialization_section);
234         } else {
235                 vtable->initialized = 1;
236                 return;
237         }
238
239         if (exc == NULL ||
240             (klass->image == mono_defaults.corlib &&            
241              !strcmp (klass->name_space, "System") &&
242              !strcmp (klass->name, "TypeInitializationException")))
243                 return; /* No static constructor found or avoid infinite loop */
244
245         if (klass->name_space && *klass->name_space)
246                 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
247         else
248                 full_name = g_strdup (klass->name);
249
250         exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
251         g_free (full_name);
252
253         mono_raise_exception (exc_to_throw);
254 }
255
256 static gpointer
257 default_trampoline (MonoMethod *method)
258 {
259         return method;
260 }
261
262 static gpointer
263 default_remoting_trampoline (MonoMethod *method)
264 {
265         g_error ("remoting not installed");
266         return NULL;
267 }
268
269 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
270 static MonoTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
271
272 void
273 mono_install_trampoline (MonoTrampoline func) 
274 {
275         arch_create_jit_trampoline = func? func: default_trampoline;
276 }
277
278 void
279 mono_install_remoting_trampoline (MonoTrampoline func) 
280 {
281         arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
282 }
283
284 static MonoCompileFunc default_mono_compile_method = NULL;
285
286 void        
287 mono_install_compile_method (MonoCompileFunc func)
288 {
289         default_mono_compile_method = func;
290 }
291
292 gpointer 
293 mono_compile_method (MonoMethod *method)
294 {
295         if (!default_mono_compile_method) {
296                 g_error ("compile method called on uninitialized runtime");
297                 return NULL;
298         }
299         return default_mono_compile_method (method);
300 }
301
302
303 #if 0 && HAVE_BOEHM_GC
304 static void
305 vtable_finalizer (void *obj, void *data) {
306         g_print ("%s finalized (%p)\n", (char*)data, obj);
307 }
308 #endif
309
310 #if CREATION_SPEEDUP
311
312 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
313
314 /*
315  * The vtables in the root appdomain are assumed to be reachable by other 
316  * roots, and we don't use typed allocation in the other domains.
317  */
318
319 #define GC_HEADER_BITMAP (1 << (G_STRUCT_OFFSET (MonoObject,synchronisation) / sizeof(gpointer)))
320
321 static void
322 mono_class_compute_gc_descriptor (MonoClass *class)
323 {
324         MonoClassField *field;
325         guint64 bitmap;
326         guint32 bm [2];
327         int i;
328         static gboolean gcj_inited = FALSE;
329
330         if (!gcj_inited) {
331                 gcj_inited = TRUE;
332
333                 GC_init_gcj_malloc (5, NULL);
334         }
335
336         if (!class->inited)
337                 mono_class_init (class);
338
339         if (class->gc_descr_inited)
340                 return;
341
342         class->gc_descr_inited = TRUE;
343         class->gc_descr = GC_NO_DESCRIPTOR;
344
345         if (class == mono_defaults.string_class) {
346                 bitmap = GC_HEADER_BITMAP;
347                 class->gc_descr = (gpointer)GC_make_descriptor ((GC_bitmap)&bitmap, 2);
348         }
349         else if (class->rank) {
350                 mono_class_compute_gc_descriptor (class->element_class);
351
352                 if (class->element_class->valuetype && (class->element_class->gc_descr != GC_NO_DESCRIPTOR) && (class->element_class->gc_bitmap == GC_HEADER_BITMAP)) {
353                         bitmap = GC_HEADER_BITMAP;
354                         if (class->rank > 1)
355                                 bitmap += 1 << (G_STRUCT_OFFSET (MonoArray,bounds) / sizeof(gpointer));
356                         class->gc_descr = (gpointer)GC_make_descriptor ((GC_bitmap)&bitmap, 3);
357                 }
358         }
359         else {
360                 static int count = 0;
361                 MonoClass *p;
362                 guint32 pos;
363
364                 /* GC 6.1 has trouble handling 64 bit descriptors... */
365                 if ((class->instance_size / sizeof (gpointer)) > 30) {
366 /*                      printf ("TOO LARGE: %s %d.\n", class->name, class->instance_size / sizeof (gpointer)); */
367                         return;
368                 }
369
370                 bitmap = GC_HEADER_BITMAP;
371
372                 count ++;
373
374 /*              if (count > 442) */
375 /*                      return;  */
376
377 /*              printf("KLASS: %s.\n", class->name); */
378
379                 for (p = class; p != NULL; p = p->parent) {
380                 for (i = 0; i < p->field.count; ++i) {
381                         field = &p->fields [i];
382                         if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
383                                 continue;
384                         if (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)
385                                 return;
386
387                         pos = field->offset / sizeof (gpointer);
388                         
389                         if (field->type->byref)
390                                 return;
391
392                         switch (field->type->type) {
393                         case MONO_TYPE_BOOLEAN:
394                         case MONO_TYPE_I1:
395                         case MONO_TYPE_U1:
396                         case MONO_TYPE_I2:
397                         case MONO_TYPE_U2:
398                         case MONO_TYPE_CHAR:
399                         case MONO_TYPE_I4:
400                         case MONO_TYPE_U4:
401                         case MONO_TYPE_I8:
402                         case MONO_TYPE_U8:
403                         case MONO_TYPE_R4:
404                         case MONO_TYPE_R8:
405 /*                              printf ("F: %s %s %d %lld %llx.\n", class->name, field->name, field->offset, ((guint64)1) << pos, bitmap); */
406                                 break;
407                         case MONO_TYPE_I:
408                         case MONO_TYPE_STRING:
409                         case MONO_TYPE_SZARRAY:
410                         case MONO_TYPE_CLASS:
411                         case MONO_TYPE_OBJECT:
412                         case MONO_TYPE_ARRAY:
413                         case MONO_TYPE_PTR:
414                                 g_assert ((field->offset % sizeof(gpointer)) == 0);
415
416                                 bitmap |= ((guint64)1) << pos;
417 /*                              printf ("F: %s %s %d %d %lld %llx.\n", class->name, field->name, field->offset, pos, ((guint64)(1)) << pos, bitmap); */
418                                 break;
419                         case MONO_TYPE_VALUETYPE: {
420                                 MonoClass *fclass = field->type->data.klass;
421                                 if (!fclass->enumtype) {
422                                         mono_class_compute_gc_descriptor (fclass);
423                                         bitmap |= (fclass->gc_bitmap >> (sizeof (MonoObject) / sizeof (gpointer))) << pos;
424                                 }
425                                 break;
426                         }
427                         default:
428                                 return;
429                         }
430                 }
431                 }
432
433 /*              printf("CLASS: %s.%s -> %d %llx.\n", class->name_space, class->name, class->instance_size / sizeof (gpointer), bitmap); */
434                 class->gc_bitmap = bitmap;
435                 /* Convert to the format expected by GC_make_descriptor */
436                 bm [0] = (guint32)bitmap;
437                 bm [1] = (guint32)(bitmap >> 32);
438                 class->gc_descr = (gpointer)GC_make_descriptor ((GC_bitmap)&bm, class->instance_size / sizeof (gpointer));
439         }
440 }
441 #endif /* CREATION_SPEEDUP */
442
443 /**
444  * field_is_special_static:
445  *
446  * Returns SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
447  * SPECIAL_STATIC_NONE otherwise.
448  */
449 static gint32
450 field_is_special_static (MonoClass *fklass, MonoClassField *field)
451 {
452         MonoCustomAttrInfo *ainfo;
453         int i;
454         ainfo = mono_custom_attrs_from_field (fklass, field);
455         if (!ainfo)
456                 return FALSE;
457         for (i = 0; i < ainfo->num_attrs; ++i) {
458                 MonoClass *klass = ainfo->attrs [i].ctor->klass;
459                 if (klass->image == mono_defaults.corlib) {
460                         if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
461                                 mono_custom_attrs_free (ainfo);
462                                 return SPECIAL_STATIC_THREAD;
463                         }
464                         else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
465                                 mono_custom_attrs_free (ainfo);
466                                 return SPECIAL_STATIC_CONTEXT;
467                         }
468                 }
469         }
470         mono_custom_attrs_free (ainfo);
471         return SPECIAL_STATIC_NONE;
472 }
473
474 /**
475  * mono_class_vtable:
476  * @domain: the application domain
477  * @class: the class to initialize
478  *
479  * VTables are domain specific because we create domain specific code, and 
480  * they contain the domain specific static class data.
481  */
482 MonoVTable *
483 mono_class_vtable (MonoDomain *domain, MonoClass *class)
484 {
485         MonoVTable *vt = NULL;
486         MonoClassField *field;
487         char *t;
488         int i;
489         guint32 vtable_size;
490         guint32 cindex;
491         guint32 constant_cols [MONO_CONSTANT_SIZE];
492
493         g_assert (class);
494
495         vt = class->cached_vtable;
496         if (vt && vt->domain == domain)
497                 return vt;
498
499         mono_domain_lock (domain);
500         if ((vt = mono_g_hash_table_lookup (domain->class_vtable_hash, class))) {
501                 mono_domain_unlock (domain);
502                 return vt;
503         }
504         
505         if (!class->inited)
506                 mono_class_init (class);
507
508         mono_stats.used_class_count++;
509         mono_stats.class_vtable_size += sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
510
511         vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
512
513         vt = mono_mempool_alloc0 (domain->mp,  vtable_size);
514
515         vt->klass = class;
516         vt->domain = domain;
517
518 #if CREATION_SPEEDUP
519         mono_class_compute_gc_descriptor (class);
520         if (domain != mono_get_root_domain ())
521                 /*
522                  * We can't use typed allocation in the non-root domains, since the
523                  * collector needs the GC descriptor stored in the vtable even after
524                  * the mempool containing the vtable is destroyed when the domain is
525                  * unloaded. An alternative might be to allocate vtables in the GC
526                  * heap, but this does not seem to work (it leads to crashes inside
527                  * libgc). If that approach is tried, two gc descriptors need to be
528                  * allocated for each class: one for the root domain, and one for all
529                  * other domains. The second descriptor should contain a bit for the
530                  * vtable field in MonoObject, since we can no longer assume the 
531                  * vtable is reachable by other roots after the appdomain is unloaded.
532                  */
533                 vt->gc_descr = GC_NO_DESCRIPTOR;
534         else
535                 vt->gc_descr = class->gc_descr;
536 #endif
537
538         if (class->class_size) {
539 #if HAVE_BOEHM_GC
540                 vt->data = GC_MALLOC (class->class_size + 8);
541                 /*vt->data = GC_debug_malloc (class->class_size + 8, class->name, 2);*/
542                 /*GC_register_finalizer (vt->data, vtable_finalizer, class->name, NULL, NULL);*/
543                 mono_g_hash_table_insert (domain->static_data_hash, class, vt->data);
544 #else
545                 vt->data = mono_mempool_alloc0 (domain->mp, class->class_size + 8);
546                 
547 #endif
548                 mono_stats.class_static_data_size += class->class_size + 8;
549         }
550
551         cindex = -1;
552         for (i = class->field.first; i < class->field.last; ++i) {
553                 field = &class->fields [i - class->field.first];
554                 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
555                         continue;
556                 if (mono_field_is_deleted (field))
557                         continue;
558                 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
559                         gint32 special_static = field_is_special_static (class, field);
560                         if (special_static != SPECIAL_STATIC_NONE) {
561                                 guint32 size, align, offset;
562                                 size = mono_type_size (field->type, &align);
563                                 offset = mono_alloc_special_static_data (special_static, size, align);
564                                 if (!domain->special_static_fields)
565                                         domain->special_static_fields = g_hash_table_new (NULL, NULL);
566                                 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
567                                 continue;
568                         }
569                 }
570                 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
571                         MonoClass *fklass = mono_class_from_mono_type (field->type);
572                         g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
573                         t = (char*)vt->data + field->offset;
574                         if (fklass->valuetype) {
575                                 memcpy (t, field->data, mono_class_value_size (fklass, NULL));
576                         } else {
577                                 /* it's a pointer type: add check */
578                                 g_assert (fklass->byval_arg.type == MONO_TYPE_PTR);
579                                 *t = *(char *)field->data;
580                         }
581                         continue;
582                 }
583                 if (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
584                         continue;
585
586                 
587                 if (!field->data) {
588                         cindex = mono_metadata_get_constant_index (class->image, MONO_TOKEN_FIELD_DEF | (i + 1), cindex + 1);
589                         g_assert (cindex);
590                         g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
591
592                         mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
593                         field->def_type = constant_cols [MONO_CONSTANT_TYPE];
594                         field->data = (gpointer)mono_metadata_blob_heap (class->image, constant_cols [MONO_CONSTANT_VALUE]);
595                 }
596                 
597                 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
598                         get_default_field_value (domain, field, (char*)vt->data + field->offset);
599         }
600
601         vt->max_interface_id = class->max_interface_id;
602         
603         vt->interface_offsets = mono_mempool_alloc0 (domain->mp, 
604                 sizeof (gpointer) * (class->max_interface_id + 1));
605
606         /* initialize interface offsets */
607         for (i = 0; i <= class->max_interface_id; ++i) {
608                 int slot = class->interface_offsets [i];
609                 if (slot >= 0)
610                         vt->interface_offsets [i] = &(vt->vtable [slot]);
611         }
612
613         /* 
614          * arch_create_jit_trampoline () can recursively call this function again
615          * because it compiles icall methods right away.
616          */
617         mono_g_hash_table_insert (domain->class_vtable_hash, class, vt);
618         if (!class->cached_vtable)
619                 class->cached_vtable = vt;
620
621         /* initialize vtable */
622         for (i = 0; i < class->vtable_size; ++i) {
623                 MonoMethod *cm;
624                
625                 if ((cm = class->vtable [i]))
626                         vt->vtable [i] = arch_create_jit_trampoline (cm);
627         }
628
629         mono_domain_unlock (domain);
630
631         /* make sure the the parent is initialized */
632         if (class->parent)
633                 mono_class_vtable (domain, class->parent);
634
635         vt->type = mono_type_get_object (domain, &class->byval_arg);
636         if (class->contextbound)
637                 vt->remote = 1;
638         else
639                 vt->remote = 0;
640
641         return vt;
642 }
643
644 /**
645  * mono_class_proxy_vtable:
646  * @domain: the application domain
647  * @remove_class: the remote class
648  *
649  * Creates a vtable for transparent proxies. It is basically
650  * a copy of the real vtable of the class wrapped in @remote_class,
651  * but all function pointers invoke the remoting functions, and
652  * vtable->klass points to the transparent proxy class, and not to @class.
653  */
654 static MonoVTable *
655 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class)
656 {
657         MonoVTable *vt, *pvt;
658         int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
659         MonoClass *k;
660         MonoClass *class = remote_class->proxy_class;
661
662         vt = mono_class_vtable (domain, class);
663         max_interface_id = vt->max_interface_id;
664
665         /* Calculate vtable space for extra interfaces */
666         for (j = 0; j < remote_class->interface_count; j++) {
667                 MonoClass* iclass = remote_class->interfaces[j];
668                 int method_count = iclass->method.count;
669         
670                 if (iclass->interface_id <= class->max_interface_id && class->interface_offsets[iclass->interface_id] != 0) 
671                         continue;       /* interface implemented by the class */
672
673                 for (i = 0; i < iclass->interface_count; i++)
674                         method_count += iclass->interfaces[i]->method.count;
675
676                 extra_interface_vtsize += method_count * sizeof (gpointer);
677                 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
678         }
679
680         vtsize = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
681
682         mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
683
684         pvt = mono_mempool_alloc (domain->mp, vtsize + extra_interface_vtsize);
685         memcpy (pvt, vt, vtsize);
686
687         pvt->klass = mono_defaults.transparent_proxy_class;
688
689         /* initialize vtable */
690         for (i = 0; i < class->vtable_size; ++i) {
691                 MonoMethod *cm;
692                     
693                 if ((cm = class->vtable [i]))
694                         pvt->vtable [i] = arch_create_remoting_trampoline (cm);
695         }
696
697         if (class->flags & TYPE_ATTRIBUTE_ABSTRACT)
698         {
699                 /* create trampolines for abstract methods */
700                 for (k = class; k; k = k->parent) {
701                         for (i = 0; i < k->method.count; i++) {
702                                 int slot = k->methods [i]->slot;
703                                 if (!pvt->vtable [slot]) 
704                                         pvt->vtable [slot] = arch_create_remoting_trampoline (k->methods[i]);
705                         }
706                 }
707         }
708
709         pvt->max_interface_id = max_interface_id;
710         pvt->interface_offsets = mono_mempool_alloc0 (domain->mp, 
711                         sizeof (gpointer) * (max_interface_id + 1));
712
713         /* initialize interface offsets */
714         for (i = 0; i <= class->max_interface_id; ++i) {
715                 int slot = class->interface_offsets [i];
716                 if (slot >= 0)
717                         pvt->interface_offsets [i] = &(pvt->vtable [slot]);
718         }
719
720         if (remote_class->interface_count > 0)
721         {
722                 int slot = class->vtable_size;
723                 MonoClass* interf;
724                 MonoClass* iclass;
725                 int n;
726
727                 /* Create trampolines for the methods of the interfaces */
728                 for (n = 0; n < remote_class->interface_count; n++) 
729                 {
730                         iclass = remote_class->interfaces[n];
731                         if (iclass->interface_id <= class->max_interface_id && class->interface_offsets[iclass->interface_id] != 0) 
732                                 continue;       /* interface implemented by the class */
733                 
734                         i = -1;
735                         interf = iclass;
736                         do {
737                                 pvt->interface_offsets [interf->interface_id] = &pvt->vtable [slot];
738         
739                                 for (j = 0; j < interf->method.count; ++j) {
740                                         MonoMethod *cm = interf->methods [j];
741                                         pvt->vtable [slot + j] = arch_create_remoting_trampoline (cm);
742                                 }
743                                 slot += interf->method.count;
744                                 if (++i < iclass->interface_count) interf = iclass->interfaces[i];
745                                 else interf = NULL;
746                                 
747                         } while (interf);
748                 }
749         }
750
751         return pvt;
752 }
753
754 /**
755  * mono_remote_class:
756  * @domain: the application domain
757  * @class_name: name of the remote class
758  *
759  * Creates and initializes a MonoRemoteClass object for a remote type. 
760  * 
761  */
762 MonoRemoteClass*
763 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
764 {
765         MonoRemoteClass *rc;
766
767         mono_domain_lock (domain);
768         rc = mono_g_hash_table_lookup (domain->proxy_vtable_hash, class_name);
769
770         if (rc) {
771                 mono_domain_unlock (domain);
772                 return rc;
773         }
774
775         rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass));
776         rc->vtable = NULL;
777         rc->interface_count = 0;
778         rc->interfaces = NULL;
779         rc->proxy_class = mono_defaults.marshalbyrefobject_class;
780         rc->proxy_class_name = mono_string_to_utf8 (class_name);
781
782         mono_g_hash_table_insert (domain->proxy_vtable_hash, class_name, rc);
783         mono_upgrade_remote_class (domain, rc, proxy_class);
784
785         if (rc->vtable == NULL)
786                 rc->vtable = mono_class_proxy_vtable (domain, rc);
787
788         mono_domain_unlock (domain);
789
790         return rc;
791 }
792
793 static void
794 extend_interface_array (MonoDomain *domain, MonoRemoteClass *remote_class, int amount)
795 {
796         /* Extends the array of interfaces. Memory is extended using blocks of 5 pointers */
797
798         int current_size = ((remote_class->interface_count / 5) + 1) * 5;
799         remote_class->interface_count += amount;
800
801         if (remote_class->interface_count > current_size || remote_class->interfaces == NULL) 
802         {
803                 int new_size = ((remote_class->interface_count / 5) + 1) * 5;
804                 MonoClass **new_array = mono_mempool_alloc (domain->mp, new_size * sizeof (MonoClass*));
805         
806                 if (remote_class->interfaces != NULL)
807                         memcpy (new_array, remote_class->interfaces, current_size * sizeof (MonoClass*));
808                 
809                 remote_class->interfaces = new_array;
810         }
811 }
812
813
814 /**
815  * mono_upgrade_remote_class:
816  * @domain: the application domain
817  * @remote_class: the remote class
818  * @klass: class to which the remote class can be casted.
819  *
820  * Updates the vtable of the remote class by adding the necessary method slots
821  * and interface offsets so it can be safely casted to klass. klass can be a
822  * class or an interface.
823  */
824 void mono_upgrade_remote_class (MonoDomain *domain, MonoRemoteClass *remote_class, MonoClass *klass)
825 {
826         gboolean redo_vtable;
827
828         mono_domain_lock (domain);
829
830         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
831                 int i;
832                 redo_vtable = TRUE;
833                 for (i = 0; i < remote_class->interface_count; i++)
834                         if (remote_class->interfaces[i] == klass) redo_vtable = FALSE;
835                                 
836                 if (redo_vtable) {
837                         extend_interface_array (domain, remote_class, 1);
838                         remote_class->interfaces [remote_class->interface_count-1] = klass;
839                 }
840         }
841         else {
842                 redo_vtable = (remote_class->proxy_class != klass);
843                 remote_class->proxy_class = klass;
844         }
845
846         if (redo_vtable)
847                 remote_class->vtable = mono_class_proxy_vtable (domain, remote_class);
848 /*
849         int n;
850         printf ("remote class upgrade - class:%s num-interfaces:%d\n", remote_class->proxy_class_name, remote_class->interface_count);
851         
852         for (n=0; n<remote_class->interface_count; n++)
853                 printf ("  I:%s\n", remote_class->interfaces[n]->name);
854 */
855
856         mono_domain_unlock (domain);
857 }
858
859 /**
860  * mono_object_get_virtual_method:
861  *
862  * Retrieve the MonoMethod that would be called on obj if obj is passed as
863  * the instance of a callvirt of method.
864  */
865 MonoMethod*
866 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method) {
867         MonoClass *klass;
868         MonoMethod **vtable;
869         gboolean is_proxy;
870         MonoMethod *res = NULL;
871
872         klass = mono_object_class (obj);
873         if (klass == mono_defaults.transparent_proxy_class) {
874                 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
875                 is_proxy = TRUE;
876         } else {
877                 is_proxy = FALSE;
878         }
879
880         if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
881                         return method;
882
883         vtable = klass->vtable;
884
885         /* check method->slot is a valid index: perform isinstance? */
886         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
887                 if (!is_proxy)
888                         res = vtable [klass->interface_offsets [method->klass->interface_id] + method->slot];
889         } else {
890                 if (method->slot != -1)
891                         res = vtable [method->slot];
892         }
893
894         if (is_proxy) {
895                 if (!res) res = method;   /* It may be an interface or abstract class method */
896                 res = mono_marshal_get_remoting_invoke (res);
897         }
898
899         g_assert (res);
900         
901         return res;
902 }
903
904 static MonoObject*
905 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
906 {
907         g_error ("runtime invoke called on uninitialized runtime");
908         return NULL;
909 }
910
911 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
912
913 /**
914  * mono_runtime_invoke:
915  *
916  * Invokes the method represented by `method' on the object `obj'.
917  *
918  * obj is the 'this' pointer, it should be NULL for static
919  * methods, a MonoObject* for object instances and a pointer to
920  * the value type for value types.
921  *
922  * The params array contains the arguments to the method with the
923  * same convention: MonoObject* pointers for object instances and
924  * pointers to the value type otherwise. 
925  * 
926  * From unmanaged code you'll usually use the
927  * mono_runtime_invoke() variant.
928  *
929  * Note that this function doesn't handle virtual methods for
930  * you, it will exec the exact method you pass: we still need to
931  * expose a function to lookup the derived class implementation
932  * of a virtual method (there are examples of this in the code,
933  * though).
934  * 
935  * You can pass NULL as the exc argument if you don't want to
936  * catch exceptions, otherwise, *exc will be set to the exception
937  * thrown, if any.  if an exception is thrown, you can't use the
938  * MonoObject* result from the function.
939  * 
940  * If the method returns a value type, it is boxed in an object
941  * reference.
942  */
943 MonoObject*
944 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
945 {
946         return default_mono_runtime_invoke (method, obj, params, exc);
947 }
948
949 static void
950 set_value (MonoType *type, void *dest, void *value, int deref_pointer) {
951         int t;
952         if (type->byref) {
953                 gpointer *p = (gpointer*)dest;
954                 *p = value;
955                 return;
956         }
957         t = type->type;
958 handle_enum:
959         switch (t) {
960         case MONO_TYPE_BOOLEAN:
961         case MONO_TYPE_I1:
962         case MONO_TYPE_U1: {
963                 guint8 *p = (guint8*)dest;
964                 *p = *(guint8*)value;
965                 return;
966         }
967         case MONO_TYPE_I2:
968         case MONO_TYPE_U2:
969         case MONO_TYPE_CHAR: {
970                 guint16 *p = (guint16*)dest;
971                 *p = *(guint16*)value;
972                 return;
973         }
974 #if SIZEOF_VOID_P == 4
975         case MONO_TYPE_I:
976         case MONO_TYPE_U:
977 #endif
978         case MONO_TYPE_I4:
979         case MONO_TYPE_U4: {
980                 gint32 *p = (gint32*)dest;
981                 *p = *(gint32*)value;
982                 return;
983         }
984 #if SIZEOF_VOID_P == 8
985         case MONO_TYPE_I:
986         case MONO_TYPE_U:
987 #endif
988         case MONO_TYPE_I8:
989         case MONO_TYPE_U8: {
990                 gint64 *p = (gint64*)dest;
991                 *p = *(gint64*)value;
992                 return;
993         }
994         case MONO_TYPE_R4: {
995                 float *p = (float*)dest;
996                 *p = *(float*)value;
997                 return;
998         }
999         case MONO_TYPE_R8: {
1000                 double *p = (double*)dest;
1001                 *p = *(double*)value;
1002                 return;
1003         }
1004         case MONO_TYPE_STRING:
1005         case MONO_TYPE_SZARRAY:
1006         case MONO_TYPE_CLASS:
1007         case MONO_TYPE_OBJECT:
1008         case MONO_TYPE_ARRAY:
1009         case MONO_TYPE_PTR: {
1010                 gpointer *p = (gpointer*)dest;
1011                 *p = deref_pointer? *(gpointer*)value: value;
1012                 return;
1013         }
1014         case MONO_TYPE_VALUETYPE:
1015                 if (type->data.klass->enumtype) {
1016                         t = type->data.klass->enum_basetype->type;
1017                         goto handle_enum;
1018                 } else {
1019                         int size;
1020                         size = mono_class_value_size (type->data.klass, NULL);
1021                         memcpy (dest, value, size);
1022                 }
1023                 return;
1024         default:
1025                 g_warning ("got type %x", type->type);
1026                 g_assert_not_reached ();
1027         }
1028 }
1029
1030 void
1031 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
1032 {
1033         void *dest;
1034
1035         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
1036
1037         dest = (char*)obj + field->offset;
1038         set_value (field->type, dest, value, FALSE);
1039 }
1040
1041 void
1042 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
1043 {
1044         void *dest;
1045
1046         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
1047         /* you cant set a constant! */
1048         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
1049         
1050         dest = (char*)vt->data + field->offset;
1051         set_value (field->type, dest, value, FALSE);
1052 }
1053
1054 void
1055 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
1056 {
1057         void *src;
1058
1059         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
1060
1061         src = (char*)obj + field->offset;
1062         set_value (field->type, value, src, TRUE);
1063 }
1064
1065 MonoObject *
1066 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
1067 {       
1068         MonoObject *o;
1069         MonoClass *klass;
1070         MonoVTable *vtable = NULL;
1071         gchar *v;
1072         gboolean is_static = FALSE;
1073         gboolean is_ref = FALSE;
1074
1075         switch (field->type->type) {
1076         case MONO_TYPE_STRING:
1077         case MONO_TYPE_OBJECT:
1078         case MONO_TYPE_CLASS:
1079         case MONO_TYPE_ARRAY:
1080         case MONO_TYPE_SZARRAY:
1081                 is_ref = TRUE;
1082                 break;
1083         case MONO_TYPE_U1:
1084         case MONO_TYPE_I1:
1085         case MONO_TYPE_BOOLEAN:
1086         case MONO_TYPE_U2:
1087         case MONO_TYPE_I2:
1088         case MONO_TYPE_CHAR:
1089         case MONO_TYPE_U:
1090         case MONO_TYPE_I:
1091         case MONO_TYPE_U4:
1092         case MONO_TYPE_I4:
1093         case MONO_TYPE_R4:
1094         case MONO_TYPE_U8:
1095         case MONO_TYPE_I8:
1096         case MONO_TYPE_R8:
1097         case MONO_TYPE_VALUETYPE:
1098                 is_ref = field->type->byref;
1099                 break;
1100         default:
1101                 g_error ("type 0x%x not handled in "
1102                          "mono_field_get_value_object", field->type->type);
1103                 return NULL;
1104         }
1105
1106         if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
1107                 is_static = TRUE;
1108                 vtable = mono_class_vtable (domain, field->parent);
1109                 if (!vtable->initialized)
1110                         mono_runtime_class_init (vtable);
1111         }
1112         
1113         if (is_ref) {
1114                 if (is_static) {
1115                         mono_field_static_get_value (vtable, field, &o);
1116                 } else {
1117                         mono_field_get_value (obj, field, &o);
1118                 }
1119                 return o;
1120         }
1121
1122         /* boxed value type */
1123         klass = mono_class_from_mono_type (field->type);
1124         o = mono_object_new (domain, klass);
1125         v = ((gchar *) o) + sizeof (MonoObject);
1126         if (is_static) {
1127                 mono_field_static_get_value (vtable, field, v);
1128         } else {
1129                 mono_field_get_value (obj, field, v);
1130         }
1131
1132         return o;
1133 }
1134
1135 static void
1136 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
1137 {
1138         const char *p = field->data;
1139         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
1140                 
1141         mono_metadata_decode_blob_size (p, &p);
1142
1143         switch (field->def_type) {
1144         case MONO_TYPE_BOOLEAN:
1145         case MONO_TYPE_U1:
1146         case MONO_TYPE_I1:
1147                 *(guint8 *) value = *p;
1148                 break;
1149         case MONO_TYPE_CHAR:
1150         case MONO_TYPE_U2:
1151         case MONO_TYPE_I2:
1152                 *(guint16*) value = read16 (p);
1153                 break;
1154         case MONO_TYPE_U4:
1155         case MONO_TYPE_I4:
1156                 *(guint32*) value = read32 (p);
1157                 break;
1158         case MONO_TYPE_U8:
1159         case MONO_TYPE_I8:
1160                 *(guint64*) value = read64 (p);
1161                 break;
1162         case MONO_TYPE_R4:
1163                 readr4 (p, (float*) value);
1164                 break;
1165         case MONO_TYPE_R8:
1166                 readr8 (p, (double*) value);
1167                 break;
1168         case MONO_TYPE_STRING:
1169                 *(gpointer*) value = mono_ldstr_metdata_sig (domain, field->data);
1170                 break;
1171         case MONO_TYPE_CLASS:
1172                 *(gpointer*) value = NULL;
1173                 break;
1174         default:
1175                 g_warning ("type 0x%02x should not be in constant table", field->def_type);
1176         }
1177 }
1178
1179 void
1180 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
1181 {
1182         void *src;
1183
1184         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
1185         
1186         if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
1187                 get_default_field_value (vt->domain, field, value);
1188                 return;
1189         }
1190
1191         src = (char*)vt->data + field->offset;
1192         set_value (field->type, value, src, TRUE);
1193 }
1194
1195 void
1196 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
1197 {
1198         default_mono_runtime_invoke (prop->set, obj, params, exc);
1199 }
1200
1201 MonoObject*
1202 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
1203 {
1204         return default_mono_runtime_invoke (prop->get, obj, params, exc);
1205 }
1206
1207
1208 MonoMethod *
1209 mono_get_delegate_invoke (MonoClass *klass)
1210 {
1211         MonoMethod *im;
1212         int i;
1213
1214         im = NULL;
1215
1216         for (i = 0; i < klass->method.count; ++i) {
1217                 if (klass->methods [i]->name[0] == 'I' && 
1218                     !strcmp ("Invoke", klass->methods [i]->name)) {
1219                         im = klass->methods [i];
1220                 }
1221         }
1222
1223         g_assert (im);
1224
1225         return im;
1226 }
1227
1228 MonoObject*
1229 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
1230 {
1231         MonoMethod *im;
1232
1233         im = mono_get_delegate_invoke (delegate->vtable->klass);
1234         g_assert (im);
1235
1236         return mono_runtime_invoke (im, delegate, params, exc);
1237 }
1238
1239 static MonoArray* main_args;
1240
1241 MonoArray*
1242 mono_runtime_get_main_args (void)
1243 {
1244         return main_args;
1245 }
1246
1247 static void
1248 fire_process_exit_event (void)
1249 {
1250         MonoClassField *field;
1251         MonoDomain *domain = mono_domain_get ();
1252         gpointer pa [2];
1253         MonoObject *delegate, *exc;
1254         
1255         field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
1256         g_assert (field);
1257
1258         if (domain != mono_get_root_domain ())
1259                 return;
1260
1261         delegate = *(MonoObject **)(((char *)domain->domain) + field->offset); 
1262         if (delegate == NULL)
1263                 return;
1264
1265         pa [0] = domain;
1266         pa [1] = NULL;
1267         mono_runtime_delegate_invoke (delegate, pa, &exc);
1268 }
1269
1270 /*
1271  * Execute a standard Main() method (argc/argv contains the
1272  * executable name). This method also sets the command line argument value
1273  * needed by System.Environment.
1274  */
1275 int
1276 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
1277                        MonoObject **exc)
1278 {
1279         int i;
1280         MonoArray *args = NULL;
1281         MonoDomain *domain = mono_domain_get ();
1282         gchar *utf8_fullpath;
1283         int result;
1284
1285         main_thread = mono_thread_current ();
1286
1287         main_args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
1288
1289         if (!g_path_is_absolute (argv [0])) {
1290                 gchar *basename = g_path_get_basename (argv [0]);
1291                 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
1292                                                     basename,
1293                                                     NULL);
1294
1295                 utf8_fullpath = mono_utf8_from_external (fullpath);
1296                 if(utf8_fullpath == NULL) {
1297                         /* Printing the arg text will cause glib to
1298                          * whinge about "Invalid UTF-8", but at least
1299                          * its relevant, and shows the problem text
1300                          * string.
1301                          */
1302                         g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
1303                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1304                         exit (-1);
1305                 }
1306
1307                 g_free (fullpath);
1308                 g_free (basename);
1309         } else {
1310                 utf8_fullpath = mono_utf8_from_external (argv[0]);
1311                 if(utf8_fullpath == NULL) {
1312                         g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
1313                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1314                         exit (-1);
1315                 }
1316         }
1317                 
1318         mono_array_set (main_args, gpointer, 0, mono_string_new (domain, utf8_fullpath));
1319         g_free (utf8_fullpath);
1320
1321         for (i = 1; i < argc; ++i) {
1322                 gchar *utf8_arg;
1323                 MonoString *arg;
1324
1325                 utf8_arg=mono_utf8_from_external (argv[i]);
1326                 if(utf8_arg==NULL) {
1327                         /* Ditto the comment about Invalid UTF-8 here */
1328                         g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
1329                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1330                         exit (-1);
1331                 }
1332                 
1333                 arg = mono_string_new (domain, utf8_arg);
1334                 mono_array_set (main_args, gpointer, i, arg);
1335         }
1336         argc--;
1337         argv++;
1338         if (method->signature->param_count) {
1339                 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
1340                 for (i = 0; i < argc; ++i) {
1341                         /* The encodings should all work, given that
1342                          * we've checked all these args for the
1343                          * main_args array.
1344                          */
1345                         MonoString *arg = mono_string_new (domain, mono_utf8_from_external (argv [i]));
1346                         mono_array_set (args, gpointer, i, arg);
1347                 }
1348         } else {
1349                 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
1350         }
1351         
1352         mono_assembly_set_main (method->klass->image->assembly);
1353
1354         result = mono_runtime_exec_main (method, args, exc);
1355         fire_process_exit_event ();
1356         return result;
1357 }
1358
1359 /* Used in mono_unhandled_exception */
1360 static MonoObject *
1361 create_unhandled_exception_eventargs (MonoObject *exc)
1362 {
1363         MonoClass *klass;
1364         gpointer args [2];
1365         MonoMethod *method = NULL;
1366         MonoBoolean is_terminating = TRUE;
1367         MonoObject *obj;
1368         gint i;
1369
1370         klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
1371         g_assert (klass);
1372
1373         mono_class_init (klass);
1374
1375         /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
1376         for (i = 0; i < klass->method.count; ++i) {
1377                 method = klass->methods [i];
1378                 if (!strcmp (".ctor", method->name) &&
1379                     method->signature->param_count == 2 &&
1380                     method->flags & METHOD_ATTRIBUTE_PUBLIC)
1381                         break;
1382                 method = NULL;
1383         }
1384
1385         g_assert (method);
1386
1387         args [0] = exc;
1388         args [1] = &is_terminating;
1389
1390         obj = mono_object_new (mono_domain_get (), klass);
1391         mono_runtime_invoke (method, obj, args, NULL);
1392
1393         return obj;
1394 }
1395
1396 /*
1397  * We call this function when we detect an unhandled exception
1398  * in the default domain.
1399  * It invokes the * UnhandledException event in AppDomain or prints
1400  * a warning to the console 
1401  */
1402 void
1403 mono_unhandled_exception (MonoObject *exc)
1404 {
1405         MonoDomain *domain = mono_domain_get ();
1406         MonoClassField *field;
1407         MonoObject *delegate;
1408         
1409         field=mono_class_get_field_from_name(mono_defaults.appdomain_class, 
1410                                              "UnhandledException");
1411         g_assert (field);
1412
1413         if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
1414                 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset); 
1415
1416                 /* set exitcode only in the main thread */
1417                 if (mono_thread_current () == main_thread)
1418                         mono_environment_exitcode_set (1);
1419                 if (domain != mono_get_root_domain () || !delegate) {
1420                         mono_print_unhandled_exception (exc);
1421                 } else {
1422                         MonoObject *e = NULL;
1423                         gpointer pa [2];
1424
1425                         pa [0] = domain->domain;
1426                         pa [1] = create_unhandled_exception_eventargs (exc);
1427                         mono_runtime_delegate_invoke (delegate, pa, &e);
1428                         
1429                         if (e) {
1430                                 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
1431                                 g_warning ("exception inside UnhandledException handler: %s\n", msg);
1432                                 g_free (msg);
1433                         }
1434                 }
1435         }
1436 }
1437
1438 /*
1439  * Launch a new thread to start all setup that requires managed code
1440  * to be executed.
1441  *
1442  * main_func is called back from the thread with main_args as the
1443  * parameter.  The callback function is expected to start Main()
1444  * eventually.  This function then waits for all managed threads to
1445  * finish.
1446  */
1447 void
1448 mono_runtime_exec_managed_code (MonoDomain *domain,
1449                                 MonoMainThreadFunc main_func,
1450                                 gpointer main_args)
1451 {
1452         mono_thread_create (domain, main_func, main_args);
1453
1454         mono_thread_manage ();
1455 }
1456
1457 /*
1458  * Execute a standard Main() method (args doesn't contain the
1459  * executable name).
1460  */
1461 int
1462 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
1463 {
1464         MonoDomain *domain;
1465         gpointer pa [1];
1466         int rval;
1467
1468         g_assert (args);
1469
1470         pa [0] = args;
1471
1472         domain = mono_object_domain (args);
1473         if (!domain->entry_assembly) {
1474                 gchar *str;
1475                 gchar *config_suffix;
1476                 MonoAssembly *assembly;
1477
1478                 assembly = method->klass->image->assembly;
1479                 domain->entry_assembly = assembly;
1480                 domain->setup->application_base = mono_string_new (domain, assembly->basedir);
1481
1482                 config_suffix = g_strconcat (assembly->aname.name, ".exe.config", NULL);
1483                 str = g_build_filename (assembly->basedir, config_suffix, NULL);
1484                 g_free (config_suffix);
1485                 domain->setup->configuration_file = mono_string_new (domain, str);
1486                 g_free (str);
1487         }
1488
1489         /* FIXME: check signature of method */
1490         if (method->signature->ret->type == MONO_TYPE_I4) {
1491                 MonoObject *res;
1492                 res = mono_runtime_invoke (method, NULL, pa, exc);
1493                 if (!exc || !*exc)
1494                         rval = *(guint32 *)((char *)res + sizeof (MonoObject));
1495                 else
1496                         rval = -1;
1497
1498                 mono_environment_exitcode_set (rval);
1499         } else {
1500                 mono_runtime_invoke (method, NULL, pa, exc);
1501                 if (!exc || !*exc)
1502                         rval = 0;
1503                 else {
1504                         /* If the return type of Main is void, only
1505                          * set the exitcode if an exception was thrown
1506                          * (we don't want to blow away an
1507                          * explicitly-set exit code)
1508                          */
1509                         rval = -1;
1510                         mono_environment_exitcode_set (rval);
1511                 }
1512         }
1513
1514         return rval;
1515 }
1516
1517 void
1518 mono_install_runtime_invoke (MonoInvokeFunc func)
1519 {
1520         default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
1521 }
1522
1523 /**
1524  * mono_runtime_invoke:
1525  *
1526  * Invokes the method represented by `method' on the object `obj'.
1527  *
1528  * obj is the 'this' pointer, it should be NULL for static
1529  * methods, a MonoObject* for object instances and a pointer to
1530  * the value type for value types.
1531  *
1532  * The params array contains the arguments to the method with the
1533  * same convention: MonoObject* pointers for object instances and
1534  * pointers to the value type otherwise. The _invoke_array
1535  * variant takes a C# object[] as the params argument (MonoArray
1536  * *params): in this case the value types are boxed inside the
1537  * respective reference representation.
1538  * 
1539  * From unmanaged code you'll usually use the
1540  * mono_runtime_invoke() variant.
1541  *
1542  * Note that this function doesn't handle virtual methods for
1543  * you, it will exec the exact method you pass: we still need to
1544  * expose a function to lookup the derived class implementation
1545  * of a virtual method (there are examples of this in the code,
1546  * though).
1547  * 
1548  * You can pass NULL as the exc argument if you don't want to
1549  * catch exceptions, otherwise, *exc will be set to the exception
1550  * thrown, if any.  if an exception is thrown, you can't use the
1551  * MonoObject* result from the function.
1552  * 
1553  * If the method returns a value type, it is boxed in an object
1554  * reference.
1555  */
1556 MonoObject*
1557 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
1558                            MonoObject **exc)
1559 {
1560         MonoMethodSignature *sig = method->signature;
1561         gpointer *pa = NULL;
1562         int i;
1563                 
1564         if (NULL != params) {
1565                 pa = alloca (sizeof (gpointer) * mono_array_length (params));
1566                 for (i = 0; i < mono_array_length (params); i++) {
1567                         if (sig->params [i]->byref) {
1568                                 /* nothing to do */
1569                         }
1570
1571                         switch (sig->params [i]->type) {
1572                         case MONO_TYPE_U1:
1573                         case MONO_TYPE_I1:
1574                         case MONO_TYPE_BOOLEAN:
1575                         case MONO_TYPE_U2:
1576                         case MONO_TYPE_I2:
1577                         case MONO_TYPE_CHAR:
1578                         case MONO_TYPE_U:
1579                         case MONO_TYPE_I:
1580                         case MONO_TYPE_U4:
1581                         case MONO_TYPE_I4:
1582                         case MONO_TYPE_U8:
1583                         case MONO_TYPE_I8:
1584                         case MONO_TYPE_R4:
1585                         case MONO_TYPE_R8:
1586                         case MONO_TYPE_VALUETYPE:
1587                                 /* MS seems to create the objects if a null is passed in */
1588                                 if (! ((gpointer *)params->vector)[i])
1589                                         ((gpointer*)params->vector)[i] = mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i]));
1590                                 pa [i] = (char *)(((gpointer *)params->vector)[i]) + sizeof (MonoObject);
1591                                 break;
1592                         case MONO_TYPE_STRING:
1593                         case MONO_TYPE_OBJECT:
1594                         case MONO_TYPE_CLASS:
1595                         case MONO_TYPE_ARRAY:
1596                         case MONO_TYPE_SZARRAY:
1597                                 if (sig->params [i]->byref)
1598                                         pa [i] = &(((gpointer *)params->vector)[i]);
1599                                 else
1600                                         pa [i] = (char *)(((gpointer *)params->vector)[i]);
1601                                 break;
1602                         default:
1603                                 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
1604                         }
1605                 }
1606         }
1607
1608         if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
1609                 void *o = obj;
1610                 if (!obj) {
1611                         obj = mono_object_new (mono_domain_get (), method->klass);
1612                         if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
1613                                 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
1614                         }
1615                         if (method->klass->valuetype)
1616                                 o = mono_object_unbox (obj);
1617                         else
1618                                 o = obj;
1619                 }
1620                 mono_runtime_invoke (method, o, pa, exc);
1621                 return obj;
1622         } else {
1623                 /* obj must be already unboxed if needed */
1624                 return mono_runtime_invoke (method, obj, pa, exc);
1625         }
1626 }
1627
1628 static void
1629 out_of_memory (size_t size)
1630 {
1631         /* 
1632          * we could allocate at program startup some memory that we could release 
1633          * back to the system at this point if we're really low on memory (ie, size is
1634          * lower than the memory we set apart)
1635          */
1636         mono_raise_exception (mono_domain_get ()->out_of_memory_ex);
1637 }
1638
1639 /**
1640  * mono_object_allocate:
1641  * @size: number of bytes to allocate
1642  *
1643  * This is a very simplistic routine until we have our GC-aware
1644  * memory allocator. 
1645  *
1646  * Returns: an allocated object of size @size, or NULL on failure.
1647  */
1648 static inline void *
1649 mono_object_allocate (size_t size)
1650 {
1651 #if HAVE_BOEHM_GC
1652         /* if this is changed to GC_debug_malloc(), we need to change also metadata/gc.c */
1653         void *o = GC_MALLOC (size);
1654 #else
1655         void *o = calloc (1, size);
1656 #endif
1657         mono_stats.new_object_count++;
1658
1659         if (!o)
1660                 out_of_memory (size);
1661         return o;
1662 }
1663
1664 #if CREATION_SPEEDUP
1665 static inline void *
1666 mono_object_allocate_spec (size_t size, void *gcdescr)
1667 {
1668         /* if this is changed to GC_debug_malloc(), we need to change also metadata/gc.c */
1669         void *o = GC_GCJ_MALLOC (size, gcdescr);
1670         mono_stats.new_object_count++;
1671
1672         if (!o)
1673                 out_of_memory (size);
1674         return o;
1675 }
1676 #endif
1677
1678 /**
1679  * mono_object_new:
1680  * @klass: the class of the object that we want to create
1681  *
1682  * Returns a newly created object whose definition is
1683  * looked up using @klass.   This will not invoke any constructors, 
1684  * so the consumer of this routine has to invoke any constructors on
1685  * its own to initialize the object.
1686  */
1687 MonoObject *
1688 mono_object_new (MonoDomain *domain, MonoClass *klass)
1689 {
1690         MONO_ARCH_SAVE_REGS;
1691         return mono_object_new_specific (mono_class_vtable (domain, klass));
1692 }
1693
1694 /**
1695  * mono_object_new_specific:
1696  * @vtable: the vtable of the object that we want to create
1697  *
1698  * Returns: A newly created object with class and domain specified
1699  * by @vtable
1700  */
1701 MonoObject *
1702 mono_object_new_specific (MonoVTable *vtable)
1703 {
1704         MonoObject *o;
1705
1706         MONO_ARCH_SAVE_REGS;
1707         
1708         if (vtable->remote)
1709         {
1710                 gpointer pa [1];
1711                 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
1712
1713                 if (im == NULL) {
1714                         MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
1715                         int i;
1716
1717                         if (!klass->inited)
1718                                 mono_class_init (klass);
1719
1720                         for (i = 0; i < klass->method.count; ++i) {
1721                                 if (!strcmp ("CreateProxyForType", klass->methods [i]->name) &&
1722                                         klass->methods [i]->signature->param_count == 1) {
1723                                         im = klass->methods [i];
1724                                         break;
1725                                 }
1726                         }
1727                         g_assert (im);
1728                         vtable->domain->create_proxy_for_type_method = im;
1729                 }
1730         
1731                 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
1732
1733                 o = mono_runtime_invoke (im, NULL, pa, NULL);           
1734                 if (o != NULL) return o;
1735         }
1736
1737         return mono_object_new_alloc_specific (vtable);
1738 }
1739
1740 MonoObject *
1741 mono_object_new_fast (MonoVTable *vtable)
1742 {
1743         MonoObject *o;
1744         MONO_ARCH_SAVE_REGS;
1745
1746 #if CREATION_SPEEDUP
1747         if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
1748                 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
1749         } else {
1750 /*              printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
1751                 o = mono_object_allocate (vtable->klass->instance_size);
1752                 o->vtable = vtable;
1753         }
1754 #else
1755         o = mono_object_allocate (vtable->klass->instance_size);
1756         o->vtable = vtable;
1757 #endif
1758         return o;
1759 }
1760
1761 MonoObject *
1762 mono_object_new_alloc_specific (MonoVTable *vtable)
1763 {
1764         MonoObject *o;
1765
1766 #if CREATION_SPEEDUP
1767         if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
1768                 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
1769         } else {
1770 /*              printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
1771                 o = mono_object_allocate (vtable->klass->instance_size);
1772                 o->vtable = vtable;
1773         }
1774 #else
1775         o = mono_object_allocate (vtable->klass->instance_size);
1776         o->vtable = vtable;
1777 #endif
1778         if (vtable->klass->has_finalize)
1779                 mono_object_register_finalizer (o);
1780         
1781         mono_profiler_allocation (o, vtable->klass);
1782         return o;
1783 }
1784
1785 /**
1786  * mono_object_new_from_token:
1787  * @image: Context where the type_token is hosted
1788  * @token: a token of the type that we want to create
1789  *
1790  * Returns: A newly created object whose definition is
1791  * looked up using @token in the @image image
1792  */
1793 MonoObject *
1794 mono_object_new_from_token  (MonoDomain *domain, MonoImage *image, guint32 token)
1795 {
1796         MonoClass *class;
1797
1798         class = mono_class_get (image, token);
1799
1800         return mono_object_new (domain, class);
1801 }
1802
1803
1804 /**
1805  * mono_object_clone:
1806  * @obj: the object to clone
1807  *
1808  * Returns: A newly created object who is a shallow copy of @obj
1809  */
1810 MonoObject *
1811 mono_object_clone (MonoObject *obj)
1812 {
1813         MonoObject *o;
1814         int size;
1815
1816         size = obj->vtable->klass->instance_size;
1817         o = mono_object_allocate (size);
1818         mono_profiler_allocation (o, obj->vtable->klass);
1819
1820         memcpy (o, obj, size);
1821
1822         if (obj->vtable->klass->has_finalize)
1823                 mono_object_register_finalizer (o);
1824         return o;
1825 }
1826
1827 /**
1828  * mono_array_clone:
1829  * @array: the array to clone
1830  *
1831  * Returns: A newly created array who is a shallow copy of @array
1832  */
1833 MonoArray*
1834 mono_array_clone (MonoArray *array)
1835 {
1836         MonoArray *o;
1837         int size, i;
1838         guint32 *sizes;
1839         MonoClass *klass = array->obj.vtable->klass;
1840
1841         MONO_ARCH_SAVE_REGS;
1842
1843         if (array->bounds == NULL) {
1844                 size = mono_array_length (array);
1845                 o = mono_array_new_full (((MonoObject *)array)->vtable->domain,
1846                                          klass, &size, NULL);
1847
1848                 size *= mono_array_element_size (klass);
1849                 memcpy (o, array, sizeof (MonoArray) + size);
1850
1851                 return o;
1852         }
1853         
1854         sizes = alloca (klass->rank * sizeof(guint32) * 2);
1855         size = mono_array_element_size (klass);
1856         for (i = 0; i < klass->rank; ++i) {
1857                 sizes [i] = array->bounds [i].length;
1858                 size *= array->bounds [i].length;
1859                 sizes [i + klass->rank] = array->bounds [i].lower_bound;
1860         }
1861         o = mono_array_new_full (((MonoObject *)array)->vtable->domain, 
1862                                  klass, sizes, sizes + klass->rank);
1863         memcpy (o, array, sizeof(MonoArray) + size);
1864
1865         return o;
1866 }
1867
1868 /* helper macros to check for overflow when calculating the size of arrays */
1869 #define MYGUINT32_MAX 4294967295U
1870 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1871         (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
1872 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1873         ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1874         (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
1875
1876 /*
1877  * mono_array_new_full:
1878  * @domain: domain where the object is created
1879  * @array_class: array class
1880  * @lengths: lengths for each dimension in the array
1881  * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
1882  *
1883  * This routine creates a new array objects with the given dimensions,
1884  * lower bounds and type.
1885  */
1886 MonoArray*
1887 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, 
1888                      guint32 *lengths, guint32 *lower_bounds)
1889 {
1890         guint32 byte_len, len;
1891         MonoObject *o;
1892         MonoArray *array;
1893         MonoArrayBounds *bounds;
1894         MonoVTable *vtable;
1895         int i;
1896
1897         if (!array_class->inited)
1898                 mono_class_init (array_class);
1899
1900         byte_len = mono_array_element_size (array_class);
1901         len = 1;
1902
1903         if (array_class->rank == 1 &&
1904             (lower_bounds == NULL || lower_bounds [0] == 0)) {
1905                 bounds = NULL;
1906                 len = lengths [0];
1907         } else {
1908         #if HAVE_BOEHM_GC
1909                 bounds = GC_MALLOC (sizeof (MonoArrayBounds) * array_class->rank);
1910         #else
1911                 bounds = g_malloc0 (sizeof (MonoArrayBounds) * array_class->rank);
1912         #endif
1913                 for (i = 0; i < array_class->rank; ++i) {
1914                         bounds [i].length = lengths [i];
1915                         if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
1916                                 out_of_memory (MYGUINT32_MAX);
1917                         len *= lengths [i];
1918                 }
1919
1920                 if (lower_bounds)
1921                         for (i = 0; i < array_class->rank; ++i)
1922                                 bounds [i].lower_bound = lower_bounds [i];
1923         }
1924
1925         if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
1926                 out_of_memory (MYGUINT32_MAX);
1927         byte_len *= len;
1928         if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
1929                 out_of_memory (MYGUINT32_MAX);
1930         byte_len += sizeof (MonoArray);
1931         /* 
1932          * Following three lines almost taken from mono_object_new ():
1933          * they need to be kept in sync.
1934          */
1935         vtable = mono_class_vtable (domain, array_class);
1936 #if CREATION_SPEEDUP
1937         if (vtable->gc_descr != GC_NO_DESCRIPTOR)
1938                 o = mono_object_allocate_spec (byte_len, vtable);
1939         else {
1940                 o = mono_object_allocate (byte_len);
1941                 o->vtable = vtable;
1942         }
1943 #else
1944         o = mono_object_allocate (byte_len);
1945         o->vtable = vtable;
1946 #endif
1947
1948         array = (MonoArray*)o;
1949
1950         array->bounds = bounds;
1951         array->max_length = len;
1952
1953         mono_profiler_allocation (o, array_class);
1954
1955         return array;
1956 }
1957
1958 /*
1959  * mono_array_new:
1960  * @domain: domain where the object is created
1961  * @eclass: element class
1962  * @n: number of array elements
1963  *
1964  * This routine creates a new szarray with @n elements of type @eclass.
1965  */
1966 MonoArray *
1967 mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
1968 {
1969         MonoClass *ac;
1970
1971         MONO_ARCH_SAVE_REGS;
1972
1973         ac = mono_array_class_get (eclass, 1);
1974         g_assert (ac != NULL);
1975
1976         return mono_array_new_specific (mono_class_vtable (domain, ac), n);
1977 }
1978
1979 /*
1980  * mono_array_new_specific:
1981  * @vtable: a vtable in the appropriate domain for an initialized class
1982  * @n: number of array elements
1983  *
1984  * This routine is a fast alternative to mono_array_new() for code which
1985  * can be sure about the domain it operates in.
1986  */
1987 MonoArray *
1988 mono_array_new_specific (MonoVTable *vtable, guint32 n)
1989 {
1990         MonoObject *o;
1991         MonoArray *ao;
1992         guint32 byte_len, elem_size;
1993
1994         MONO_ARCH_SAVE_REGS;
1995
1996         elem_size = mono_array_element_size (vtable->klass);
1997         if (CHECK_MUL_OVERFLOW_UN (n, elem_size))
1998                 out_of_memory (MYGUINT32_MAX);
1999         byte_len = n * elem_size;
2000         if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
2001                 out_of_memory (MYGUINT32_MAX);
2002         byte_len += sizeof (MonoArray);
2003 #if CREATION_SPEEDUP
2004         if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2005                 o = mono_object_allocate_spec (byte_len, vtable);
2006         } else {
2007 /*              printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
2008                 o = mono_object_allocate (byte_len);
2009                 o->vtable = vtable;
2010         }
2011 #else
2012         o = mono_object_allocate (byte_len);
2013         o->vtable = vtable;
2014 #endif
2015
2016         ao = (MonoArray *)o;
2017         ao->bounds = NULL;
2018         ao->max_length = n;
2019         mono_profiler_allocation (o, vtable->klass);
2020
2021         return ao;
2022 }
2023
2024 /**
2025  * mono_string_new_utf16:
2026  * @text: a pointer to an utf16 string
2027  * @len: the length of the string
2028  *
2029  * Returns: A newly created string object which contains @text.
2030  */
2031 MonoString *
2032 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
2033 {
2034         MonoString *s;
2035         
2036         s = mono_string_new_size (domain, len);
2037         g_assert (s != NULL);
2038
2039         memcpy (mono_string_chars (s), text, len * 2);
2040
2041         return s;
2042 }
2043
2044 /**
2045  * mono_string_new_size:
2046  * @text: a pointer to an utf16 string
2047  * @len: the length of the string
2048  *
2049  * Returns: A newly created string object of @len
2050  */
2051 MonoString *
2052 mono_string_new_size (MonoDomain *domain, gint32 len)
2053 {
2054         MonoString *s;
2055         MonoVTable *vtable;
2056         size_t size = (sizeof (MonoString) + ((len + 1) * 2));
2057
2058         /* overflow ? can't fit it, can't allocate it! */
2059         if (len > size)
2060                 out_of_memory (-1);
2061
2062         vtable = mono_class_vtable (domain, mono_defaults.string_class);
2063
2064 #if CREATION_SPEEDUP
2065         if (vtable->gc_descr != GC_NO_DESCRIPTOR)
2066                 s = mono_object_allocate_spec (size, vtable);
2067         else {
2068                 s = (MonoString*)mono_object_allocate (size);
2069                 s->object.vtable = vtable;
2070         }
2071 #else
2072         s = (MonoString*)mono_object_allocate (size);
2073         s->object.vtable = vtable;
2074 #endif
2075
2076         s->length = len;
2077         mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
2078
2079         return s;
2080 }
2081
2082 /*
2083  * mono_string_new_len:
2084  * @text: a pointer to an utf8 string
2085  * @length: number of bytes in @text to consider
2086  *
2087  * Returns: A newly created string object which contains @text.
2088  */
2089 MonoString*
2090 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
2091 {
2092         GError *error = NULL;
2093         MonoString *o = NULL;
2094         guint16 *ut;
2095         glong items_written;
2096
2097         ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
2098
2099         if (!error)
2100                 o = mono_string_new_utf16 (domain, ut, items_written);
2101         else 
2102                 g_error_free (error);
2103
2104         g_free (ut);
2105
2106         return o;
2107 }
2108
2109 /**
2110  * mono_string_new:
2111  * @text: a pointer to an utf8 string
2112  *
2113  * Returns: A newly created string object which contains @text.
2114  */
2115 MonoString*
2116 mono_string_new (MonoDomain *domain, const char *text)
2117 {
2118         GError *error = NULL;
2119         MonoString *o = NULL;
2120         guint16 *ut;
2121         glong items_written;
2122         int l;
2123
2124         l = strlen (text);
2125         
2126         ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
2127
2128         if (!error)
2129                 o = mono_string_new_utf16 (domain, ut, items_written);
2130         else 
2131                 g_error_free (error);
2132
2133         g_free (ut);
2134
2135         return o;
2136 }
2137
2138 /*
2139  * mono_string_new_wrapper:
2140  * @text: pointer to utf8 characters.
2141  *
2142  * Helper function to create a string object from @text in the current domain.
2143  */
2144 MonoString*
2145 mono_string_new_wrapper (const char *text)
2146 {
2147         MonoDomain *domain = mono_domain_get ();
2148
2149         MONO_ARCH_SAVE_REGS;
2150
2151         if (text)
2152                 return mono_string_new (domain, text);
2153
2154         return NULL;
2155 }
2156
2157 /**
2158  * mono_value_box:
2159  * @class: the class of the value
2160  * @value: a pointer to the unboxed data
2161  *
2162  * Returns: A newly created object which contains @value.
2163  */
2164 MonoObject *
2165 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
2166 {
2167         MonoObject *res;
2168         int size;
2169         MonoVTable *vtable;
2170
2171         g_assert (class->valuetype);
2172
2173         vtable = mono_class_vtable (domain, class);
2174         size = mono_class_instance_size (class);
2175         res = mono_object_allocate (size);
2176         res->vtable = vtable;
2177         mono_profiler_allocation (res, class);
2178
2179         size = size - sizeof (MonoObject);
2180
2181 #if NO_UNALIGNED_ACCESS
2182         memcpy ((char *)res + sizeof (MonoObject), value, size);
2183 #else
2184         switch (size) {
2185         case 1:
2186                 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
2187                 break;
2188         case 2:
2189                 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
2190                 break;
2191         case 4:
2192                 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
2193                 break;
2194         case 8:
2195                 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
2196                 break;
2197         default:
2198                 memcpy ((char *)res + sizeof (MonoObject), value, size);
2199         }
2200 #endif
2201         if (class->has_finalize)
2202                 mono_object_register_finalizer (res);
2203         return res;
2204 }
2205
2206 MonoDomain*
2207 mono_object_get_domain (MonoObject *obj)
2208 {
2209         return mono_object_domain (obj);
2210 }
2211
2212 MonoClass*
2213 mono_object_get_class (MonoObject *obj)
2214 {
2215         return mono_object_class (obj);
2216 }
2217
2218 gpointer
2219 mono_object_unbox (MonoObject *obj)
2220 {
2221         /* add assert for valuetypes? */
2222         g_assert (obj->vtable->klass->valuetype);
2223         return ((char*)obj) + sizeof (MonoObject);
2224 }
2225
2226 /**
2227  * mono_object_isinst:
2228  * @obj: an object
2229  * @klass: a pointer to a class 
2230  *
2231  * Returns: @obj if @obj is derived from @klass
2232  */
2233 MonoObject *
2234 mono_object_isinst (MonoObject *obj, MonoClass *klass)
2235 {
2236         if (!klass->inited)
2237                 mono_class_init (klass);
2238
2239         if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) 
2240                 return mono_object_isinst_mbyref (obj, klass);
2241
2242         if (!obj)
2243                 return NULL;
2244
2245         return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
2246 }
2247
2248 MonoObject *
2249 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
2250 {
2251         MonoVTable *vt;
2252
2253         if (!obj)
2254                 return NULL;
2255
2256         vt = obj->vtable;
2257         
2258         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2259                 if ((klass->interface_id <= vt->max_interface_id) &&
2260                     (vt->interface_offsets [klass->interface_id] != 0))
2261                         return obj;
2262         }
2263         else {
2264                 MonoClass *oklass = vt->klass;
2265                 if ((oklass == mono_defaults.transparent_proxy_class))
2266                         oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2267         
2268                 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
2269                         return obj;
2270         }
2271
2272         if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info) 
2273         {
2274                 MonoDomain *domain = mono_domain_get ();
2275                 MonoObject *res;
2276                 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
2277                 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
2278                 MonoMethod *im = NULL;
2279                 gpointer pa [2];
2280                 int i;
2281         
2282                 for (i = 0; i < rpklass->method.count; ++i) {
2283                         if (!strcmp ("CanCastTo", rpklass->methods [i]->name)) {
2284                                 im = rpklass->methods [i];
2285                                 break;
2286                         }
2287                 }
2288         
2289                 im = mono_object_get_virtual_method (rp, im);
2290                 g_assert (im);
2291         
2292                 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
2293                 pa [1] = obj;
2294
2295                 res = mono_runtime_invoke (im, rp, pa, NULL);
2296         
2297                 if (*(MonoBoolean *) mono_object_unbox(res)) {
2298                         /* Update the vtable of the remote type, so it can safely cast to this new type */
2299                         mono_upgrade_remote_class (domain, ((MonoTransparentProxy *)obj)->remote_class, klass);
2300                         obj->vtable = ((MonoTransparentProxy *)obj)->remote_class->vtable;
2301                         return obj;
2302                 }
2303         }
2304
2305         return NULL;
2306 }
2307
2308 /**
2309  * mono_object_castclass_mbyref:
2310  * @obj: an object
2311  * @klass: a pointer to a class 
2312  *
2313  * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
2314  */
2315 MonoObject *
2316 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
2317 {
2318         if (!obj) return NULL;
2319         if (mono_object_isinst_mbyref (obj, klass)) return obj;
2320                 
2321         mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
2322                                                         "System",
2323                                                         "InvalidCastException"));
2324         return NULL;
2325 }
2326
2327 typedef struct {
2328         MonoDomain *orig_domain;
2329         char *ins;
2330         MonoString *res;
2331 } LDStrInfo;
2332
2333 static void
2334 str_lookup (MonoDomain *domain, gpointer user_data)
2335 {
2336         LDStrInfo *info = user_data;
2337         if (info->res || domain == info->orig_domain)
2338                 return;
2339         mono_domain_lock (domain);
2340         info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
2341         mono_domain_unlock (domain);
2342 }
2343
2344 static MonoString*
2345 mono_string_is_interned_lookup (MonoString *str, int insert)
2346 {
2347         MonoGHashTable *ldstr_table;
2348         MonoString *res;
2349         MonoDomain *domain;
2350         char *ins = g_malloc (4 + str->length * 2);
2351         char *p;
2352         
2353         /* Encode the length */
2354         /* Same code as in mono_image_insert_string () */
2355         p = ins;
2356         mono_metadata_encode_value (1 | (2 * str->length), p, &p);
2357
2358         /*
2359          * ins is stored in the hash table as a key and needs to have the same
2360          * representation as in the metadata: we swap the character bytes on big
2361          * endian boxes.
2362          */
2363 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
2364         {
2365                 int i;
2366                 char *p2 = (char *)mono_string_chars (str);
2367                 for (i = 0; i < str->length; ++i) {
2368                         *p++ = p2 [1];
2369                         *p++ = p2 [0];
2370                         p2 += 2;
2371                 }
2372         }
2373 #else
2374         memcpy (p, mono_string_chars (str), str->length * 2);
2375 #endif
2376         domain = ((MonoObject *)str)->vtable->domain;
2377         ldstr_table = domain->ldstr_table;
2378         mono_domain_lock (domain);
2379         if ((res = mono_g_hash_table_lookup (ldstr_table, ins))) {
2380                 mono_domain_unlock (domain);
2381                 g_free (ins);
2382                 return res;
2383         }
2384         if (insert) {
2385                 mono_g_hash_table_insert (ldstr_table, ins, str);
2386                 mono_domain_unlock (domain);
2387                 return str;
2388         } else {
2389                 LDStrInfo ldstr_info;
2390                 ldstr_info.orig_domain = domain;
2391                 ldstr_info.ins = ins;
2392                 ldstr_info.res = NULL;
2393
2394                 mono_domain_foreach (str_lookup, &ldstr_info);
2395                 if (ldstr_info.res) {
2396                         /* 
2397                          * the string was already interned in some other domain:
2398                          * intern it in the current one as well.
2399                          */
2400                         mono_g_hash_table_insert (ldstr_table, ins, str);
2401                         mono_domain_unlock (domain);
2402                         return str;
2403                 }
2404         }
2405         mono_domain_unlock (domain);
2406         g_free (ins);
2407         return NULL;
2408 }
2409
2410 MonoString*
2411 mono_string_is_interned (MonoString *o)
2412 {
2413         return mono_string_is_interned_lookup (o, FALSE);
2414 }
2415
2416 MonoString*
2417 mono_string_intern (MonoString *str)
2418 {
2419         return mono_string_is_interned_lookup (str, TRUE);
2420 }
2421
2422 /*
2423  * mono_ldstr:
2424  * @domain: the domain where the string will be used.
2425  * @image: a metadata context
2426  * @idx: index into the user string table.
2427  * 
2428  * Implementation for the ldstr opcode.
2429  */
2430 MonoString*
2431 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
2432 {
2433         MONO_ARCH_SAVE_REGS;
2434
2435         if (image->dynamic)
2436                 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx);
2437         else
2438                 return mono_ldstr_metdata_sig (domain, mono_metadata_user_string (image, idx));
2439 }
2440
2441 /*
2442  * mono_ldstr_metdata_sig
2443  * @domain: the domain for the string
2444  * @sig: the signature of a metadata string
2445  *
2446  * returns a MonoString for a string stored in the metadata
2447  */
2448 static MonoString*
2449 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig)
2450 {
2451         const char *str = sig;
2452         MonoString *o;
2453         size_t len2;
2454         
2455         mono_domain_lock (domain);
2456         if ((o = mono_g_hash_table_lookup (domain->ldstr_table, sig))) {
2457                 mono_domain_unlock (domain);
2458                 return o;
2459         }
2460         
2461         len2 = mono_metadata_decode_blob_size (str, &str);
2462         len2 >>= 1;
2463
2464         o = mono_string_new_utf16 (domain, (guint16*)str, len2);
2465 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
2466         {
2467                 int i;
2468                 guint16 *p2 = (guint16*)mono_string_chars (o);
2469                 for (i = 0; i < len2; ++i) {
2470                         *p2 = GUINT16_FROM_LE (*p2);
2471                         ++p2;
2472                 }
2473         }
2474 #endif
2475         mono_g_hash_table_insert (domain->ldstr_table, (gpointer)sig, o);
2476         mono_domain_unlock (domain);
2477
2478         return o;
2479 }
2480
2481 /*
2482  * mono_string_to_utf8:
2483  * @s: a System.String
2484  *
2485  * Return the UTF8 representation for @s.
2486  * the resulting buffer nedds to be freed with g_free().
2487  */
2488 char *
2489 mono_string_to_utf8 (MonoString *s)
2490 {
2491         char *as;
2492         GError *error = NULL;
2493
2494         if (s == NULL)
2495                 return NULL;
2496
2497         if (!s->length)
2498                 return g_strdup ("");
2499
2500         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, NULL, &error);
2501         if (error) {
2502                 g_warning (error->message);
2503                 g_error_free (error);
2504         }
2505
2506         return as;
2507 }
2508
2509 /*
2510  * mono_string_to_utf16:
2511  * @s: a MonoString
2512  *
2513  * Return an null-terminated array of the utf-16 chars
2514  * contained in @s. The result must be freed with g_free().
2515  * This is a temporary helper until our string implementation
2516  * is reworked to always include the null terminating char.
2517  */
2518 gunichar2 *
2519 mono_string_to_utf16 (MonoString *s)
2520 {
2521         char *as;
2522
2523         if (s == NULL)
2524                 return NULL;
2525
2526         as = g_malloc ((s->length * 2) + 2);
2527         as [(s->length * 2)] = '\0';
2528         as [(s->length * 2) + 1] = '\0';
2529
2530         if (!s->length) {
2531                 return (gunichar2 *)(as);
2532         }
2533         
2534         memcpy (as, mono_string_chars(s), s->length * 2);
2535         return (gunichar2 *)(as);
2536 }
2537
2538 /*
2539  * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString
2540  */
2541 MonoString *
2542 mono_string_from_utf16 (gunichar2 *data)
2543 {
2544         MonoDomain *domain = mono_domain_get ();
2545         int len = 0;
2546
2547         if (!data)
2548                 return NULL;
2549
2550         while (data [len]) len++;
2551
2552         return mono_string_new_utf16 (domain, data, len);
2553 }
2554
2555 static void
2556 default_ex_handler (MonoException *ex)
2557 {
2558         MonoObject *o = (MonoObject*)ex;
2559         g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
2560         exit (1);
2561 }
2562
2563 static MonoExceptionFunc ex_handler = default_ex_handler;
2564
2565 void
2566 mono_install_handler        (MonoExceptionFunc func)
2567 {
2568         ex_handler = func? func: default_ex_handler;
2569 }
2570
2571 /*
2572  * mono_raise_exception:
2573  * @ex: exception object
2574  *
2575  * Signal the runtime that the exception @ex has been raised in unmanaged code.
2576  */
2577 void
2578 mono_raise_exception (MonoException *ex) 
2579 {
2580         /*
2581          * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
2582          * that will cause gcc to omit the function epilog, causing problems when
2583          * the JIT tries to walk the stack, since the return address on the stack
2584          * will point into the next function in the executable, not this one.
2585          */
2586
2587         ex_handler (ex);
2588 }
2589
2590 MonoWaitHandle *
2591 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
2592 {
2593         MonoWaitHandle *res;
2594
2595         res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
2596
2597         res->handle = handle;
2598
2599         return res;
2600 }
2601
2602 MonoAsyncResult *
2603 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data)
2604 {
2605         MonoAsyncResult *res;
2606
2607         res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
2608
2609         res->data = data;
2610         res->async_state = state;
2611         if (handle != NULL)
2612                 res->handle = (MonoObject *) mono_wait_handle_new (domain, handle);
2613
2614         res->sync_completed = FALSE;
2615         res->completed = FALSE;
2616
2617         return res;
2618 }
2619
2620 void
2621 mono_message_init (MonoDomain *domain,
2622                    MonoMethodMessage *this, 
2623                    MonoReflectionMethod *method,
2624                    MonoArray *out_args)
2625 {
2626         MonoMethodSignature *sig = method->method->signature;
2627         MonoString *name;
2628         int i, j;
2629         char **names;
2630         guint8 arg_type;
2631
2632         this->method = method;
2633
2634         this->args = mono_array_new (domain, mono_defaults.object_class, sig->param_count);
2635         this->arg_types = mono_array_new (domain, mono_defaults.byte_class, sig->param_count);
2636         this->async_result = NULL;
2637         this->call_type = CallType_Sync;
2638
2639         names = g_new (char *, sig->param_count);
2640         mono_method_get_param_names (method->method, (const char **) names);
2641         this->names = mono_array_new (domain, mono_defaults.string_class, sig->param_count);
2642         
2643         for (i = 0; i < sig->param_count; i++) {
2644                  name = mono_string_new (domain, names [i]);
2645                  mono_array_set (this->names, gpointer, i, name);       
2646         }
2647
2648         g_free (names);
2649         for (i = 0, j = 0; i < sig->param_count; i++) {
2650
2651                 if (sig->params [i]->byref) {
2652                         if (out_args) {
2653                                 gpointer arg = mono_array_get (out_args, gpointer, j);
2654                                 mono_array_set (this->args, gpointer, i, arg);
2655                                 j++;
2656                         }
2657                         arg_type = 2;
2658                         if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
2659                                 arg_type |= 1;
2660                 } else {
2661                         arg_type = 1;
2662                 }
2663                 mono_array_set (this->arg_types, guint8, i, arg_type);
2664         }
2665 }
2666
2667 /**
2668  * mono_remoting_invoke:
2669  * @real_proxy: pointer to a RealProxy object
2670  * @msg: The MonoMethodMessage to execute
2671  * @exc: used to store exceptions
2672  * @out_args: used to store output arguments
2673  *
2674  * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
2675  * IMessage interface and it is not trivial to extract results from there. So
2676  * we call an helper method PrivateInvoke instead of calling
2677  * RealProxy::Invoke() directly.
2678  *
2679  * Returns: the result object.
2680  */
2681 MonoObject *
2682 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, 
2683                       MonoObject **exc, MonoArray **out_args)
2684 {
2685         MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
2686         gpointer pa [4];
2687
2688         /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
2689
2690         if (!im) {
2691                 MonoClass *klass;
2692                 int i;
2693
2694                 klass = mono_defaults.real_proxy_class; 
2695                        
2696                 for (i = 0; i < klass->method.count; ++i) {
2697                         if (!strcmp ("PrivateInvoke", klass->methods [i]->name) &&
2698                             klass->methods [i]->signature->param_count == 4) {
2699                                 im = klass->methods [i];
2700                                 break;
2701                         }
2702                 }
2703         
2704                 g_assert (im);
2705                 real_proxy->vtable->domain->private_invoke_method = im;
2706         }
2707
2708         pa [0] = real_proxy;
2709         pa [1] = msg;
2710         pa [2] = exc;
2711         pa [3] = out_args;
2712
2713         return mono_runtime_invoke (im, NULL, pa, exc);
2714 }
2715
2716 MonoObject *
2717 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
2718                      MonoObject **exc, MonoArray **out_args) 
2719 {
2720         MonoDomain *domain; 
2721         MonoMethod *method;
2722         MonoMethodSignature *sig;
2723         int i, j, outarg_count = 0;
2724
2725         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
2726
2727                 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
2728                 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
2729                         target = tp->rp->unwrapped_server;
2730                 } else {
2731                         return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
2732                 }
2733         }
2734
2735         domain = mono_domain_get (); 
2736         method = msg->method->method;
2737         sig = method->signature;
2738
2739         for (i = 0; i < sig->param_count; i++) {
2740                 if (sig->params [i]->byref) 
2741                         outarg_count++;
2742         }
2743
2744         *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
2745         *exc = NULL;
2746
2747         for (i = 0, j = 0; i < sig->param_count; i++) {
2748                 if (sig->params [i]->byref) {
2749                         gpointer arg;
2750                         arg = mono_array_get (msg->args, gpointer, i);
2751                         mono_array_set (*out_args, gpointer, j, arg);
2752                         j++;
2753                 }
2754         }
2755
2756         return mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
2757 }
2758
2759 void
2760 mono_print_unhandled_exception (MonoObject *exc)
2761 {
2762         char *message = (char *) "";
2763         MonoString *str; 
2764         MonoMethod *method;
2765         MonoClass *klass;
2766         gboolean free_message = FALSE;
2767         gint i;
2768
2769         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
2770                 klass = exc->vtable->klass;
2771                 method = NULL;
2772                 while (klass && method == NULL) {
2773                         for (i = 0; i < klass->method.count; ++i) {
2774                                 method = klass->methods [i];
2775                                 if (!strcmp ("ToString", method->name) &&
2776                                     method->signature->param_count == 0 &&
2777                                     method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
2778                                     method->flags & METHOD_ATTRIBUTE_PUBLIC) {
2779                                         break;
2780                                 }
2781                                 method = NULL;
2782                         }
2783                         
2784                         if (method == NULL)
2785                                 klass = klass->parent;
2786                 }
2787
2788                 g_assert (method);
2789
2790                 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
2791                 if (str) {
2792                         message = mono_string_to_utf8 (str);
2793                         free_message = TRUE;
2794                 }
2795         }                               
2796
2797         /*
2798          * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space, 
2799          *         exc->vtable->klass->name, message);
2800          */
2801         g_printerr ("\nUnhandled Exception: %s\n", message);
2802         
2803         if (free_message)
2804                 g_free (message);
2805 }
2806
2807 /**
2808  * mono_delegate_ctor:
2809  * @this: pointer to an uninitialized delegate object
2810  * @target: target object
2811  * @addr: pointer to native code
2812  *
2813  * This is used to initialize a delegate. We also insert the method_info if
2814  * we find the info with mono_jit_info_table_find().
2815  */
2816 void
2817 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
2818 {
2819         MonoDomain *domain = mono_domain_get ();
2820         MonoDelegate *delegate = (MonoDelegate *)this;
2821         MonoMethod *method = NULL;
2822         MonoClass *class;
2823         MonoJitInfo *ji;
2824
2825         g_assert (this);
2826         g_assert (addr);
2827
2828         class = this->vtable->klass;
2829
2830         if ((ji = mono_jit_info_table_find (domain, addr))) {
2831                 method = ji->method;
2832                 delegate->method_info = mono_method_get_object (domain, method, NULL);
2833         }
2834
2835         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
2836                 g_assert (method);
2837                 method = mono_marshal_get_remoting_invoke (method);
2838                 delegate->method_ptr = mono_compile_method (method);
2839                 delegate->target = target;
2840         } else {
2841                 delegate->method_ptr = addr;
2842                 delegate->target = target;
2843         }
2844 }
2845
2846 /**
2847  * mono_method_call_message_new:
2848  *
2849  * Translates arguments pointers into a Message.
2850  */
2851 MonoMethodMessage *
2852 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke, 
2853                               MonoDelegate **cb, MonoObject **state)
2854 {
2855         MonoDomain *domain = mono_domain_get ();
2856         MonoMethodSignature *sig = method->signature;
2857         MonoMethodMessage *msg;
2858         int i, count, type;
2859
2860         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class); 
2861         
2862         if (invoke) {
2863                 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
2864                 count =  sig->param_count - 2;
2865         } else {
2866                 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
2867                 count =  sig->param_count;
2868         }
2869
2870         for (i = 0; i < count; i++) {
2871                 gpointer vpos;
2872                 MonoClass *class;
2873                 MonoObject *arg;
2874
2875                 if (sig->params [i]->byref)
2876                         vpos = *((gpointer *)params [i]);
2877                 else 
2878                         vpos = params [i];
2879
2880                 type = sig->params [i]->type;
2881                 class = mono_class_from_mono_type (sig->params [i]);
2882
2883                 if (class->valuetype)
2884                         arg = mono_value_box (domain, class, vpos);
2885                 else 
2886                         arg = *((MonoObject **)vpos);
2887                       
2888                 mono_array_set (msg->args, gpointer, i, arg);
2889         }
2890
2891         if (cb != NULL && state != NULL) {
2892                 *cb = *((MonoDelegate **)params [i]);
2893                 i++;
2894                 *state = *((MonoObject **)params [i]);
2895         }
2896
2897         return msg;
2898 }
2899
2900 /**
2901  * mono_method_return_message_restore:
2902  *
2903  * Restore results from message based processing back to arguments pointers
2904  */
2905 void
2906 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
2907 {
2908         MonoMethodSignature *sig = method->signature;
2909         int i, j, type, size;
2910         for (i = 0, j = 0; i < sig->param_count; i++) {
2911                 MonoType *pt = sig->params [i];
2912
2913                 if (pt->byref) {
2914                         char *arg = mono_array_get (out_args, gpointer, j);
2915                         type = pt->type;
2916
2917                         switch (type) {
2918                         case MONO_TYPE_VOID:
2919                                 g_assert_not_reached ();
2920                                 break;
2921                         case MONO_TYPE_U1:
2922                         case MONO_TYPE_I1:
2923                         case MONO_TYPE_BOOLEAN:
2924                         case MONO_TYPE_U2:
2925                         case MONO_TYPE_I2:
2926                         case MONO_TYPE_CHAR:
2927                         case MONO_TYPE_U4:
2928                         case MONO_TYPE_I4:
2929                         case MONO_TYPE_I8:
2930                         case MONO_TYPE_U8:
2931                         case MONO_TYPE_R4:
2932                         case MONO_TYPE_R8:
2933                         case MONO_TYPE_VALUETYPE: {
2934                                 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
2935                                 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size); 
2936                                 break;
2937                         }
2938                         case MONO_TYPE_STRING:
2939                         case MONO_TYPE_CLASS: 
2940                         case MONO_TYPE_ARRAY:
2941                         case MONO_TYPE_SZARRAY:
2942                         case MONO_TYPE_OBJECT:
2943                                 **((MonoObject ***)params [i]) = (MonoObject *)arg;
2944                                 break;
2945                         default:
2946                                 g_assert_not_reached ();
2947                         }
2948
2949                         j++;
2950                 }
2951         }
2952 }
2953
2954 /**
2955  * mono_load_remote_field:
2956  * @this: pointer to an object
2957  * @klass: klass of the object containing @field
2958  * @field: the field to load
2959  * @res: a storage to store the result
2960  *
2961  * This method is called by the runtime on attempts to load fields of
2962  * transparent proxy objects. @this points to such TP, @klass is the class of
2963  * the object containing @field. @res is a storage location which can be
2964  * used to store the result.
2965  *
2966  * Returns: an address pointing to the value of field.
2967  */
2968 gpointer
2969 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
2970 {
2971         static MonoMethod *getter = NULL;
2972         MonoDomain *domain = mono_domain_get ();
2973         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
2974         MonoClass *field_class;
2975         MonoMethodMessage *msg;
2976         MonoArray *out_args;
2977         MonoObject *exc;
2978         gpointer tmp;
2979
2980         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
2981
2982         if (!res)
2983                 res = &tmp;
2984
2985         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
2986                 mono_field_get_value (tp->rp->unwrapped_server, field, res);
2987                 return res;
2988         }
2989         
2990         if (!getter) {
2991                 int i;
2992
2993                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
2994                         MonoMethod *cm = mono_defaults.object_class->methods [i];
2995                
2996                         if (!strcmp (cm->name, "FieldGetter")) {
2997                                 getter = cm;
2998                                 break;
2999                         }
3000                 }
3001                 g_assert (getter);
3002         }
3003         
3004         field_class = mono_class_from_mono_type (field->type);
3005
3006         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3007         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
3008         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
3009
3010         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3011         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3012
3013         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3014
3015         if (exc) mono_raise_exception ((MonoException *)exc);
3016
3017         *res = mono_array_get (out_args, MonoObject *, 0);
3018
3019         if (field_class->valuetype) {
3020                 return ((char *)*res) + sizeof (MonoObject);
3021         } else
3022                 return res;
3023 }
3024
3025 MonoObject *
3026 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
3027 {
3028         static MonoMethod *getter = NULL;
3029         MonoDomain *domain = mono_domain_get ();
3030         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3031         MonoClass *field_class;
3032         MonoMethodMessage *msg;
3033         MonoArray *out_args;
3034         MonoObject *exc, *res;
3035
3036         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3037
3038         field_class = mono_class_from_mono_type (field->type);
3039
3040         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3041                 gpointer val;
3042                 if (field_class->valuetype) {
3043                         res = mono_object_new (domain, field_class);
3044                         val = ((gchar *) res) + sizeof (MonoObject);
3045                 } else {
3046                         val = &res;
3047                 }
3048                 mono_field_get_value (tp->rp->unwrapped_server, field, val);
3049                 return res;
3050         }
3051
3052         if (!getter) {
3053                 int i;
3054
3055                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
3056                         MonoMethod *cm = mono_defaults.object_class->methods [i];
3057                
3058                         if (!strcmp (cm->name, "FieldGetter")) {
3059                                 getter = cm;
3060                                 break;
3061                         }
3062                 }
3063                 g_assert (getter);
3064         }
3065         
3066         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3067         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
3068         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
3069
3070         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3071         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3072
3073         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3074
3075         if (exc) mono_raise_exception ((MonoException *)exc);
3076
3077         res = mono_array_get (out_args, MonoObject *, 0);
3078
3079         return res;
3080 }
3081
3082 /**
3083  * mono_store_remote_field:
3084  * @this: pointer to an object
3085  * @klass: klass of the object containing @field
3086  * @field: the field to load
3087  * @val: the value/object to store
3088  *
3089  * This method is called by the runtime on attempts to store fields of
3090  * transparent proxy objects. @this points to such TP, @klass is the class of
3091  * the object containing @field. @val is the new value to store in @field.
3092  */
3093 void
3094 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
3095 {
3096         static MonoMethod *setter = NULL;
3097         MonoDomain *domain = mono_domain_get ();
3098         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3099         MonoClass *field_class;
3100         MonoMethodMessage *msg;
3101         MonoArray *out_args;
3102         MonoObject *exc;
3103         MonoObject *arg;
3104
3105         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3106
3107         field_class = mono_class_from_mono_type (field->type);
3108
3109         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3110                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
3111                 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
3112                 return;
3113         }
3114
3115         if (!setter) {
3116                 int i;
3117
3118                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
3119                         MonoMethod *cm = mono_defaults.object_class->methods [i];
3120                
3121                         if (!strcmp (cm->name, "FieldSetter")) {
3122                                 setter = cm;
3123                                 break;
3124                         }
3125                 }
3126                 g_assert (setter);
3127         }
3128
3129         if (field_class->valuetype)
3130                 arg = mono_value_box (domain, field_class, val);
3131         else 
3132                 arg = *((MonoObject **)val);
3133                 
3134
3135         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3136         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
3137
3138         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3139         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3140         mono_array_set (msg->args, gpointer, 2, arg);
3141
3142         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3143
3144         if (exc) mono_raise_exception ((MonoException *)exc);
3145 }
3146
3147 void
3148 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
3149 {
3150         static MonoMethod *setter = NULL;
3151         MonoDomain *domain = mono_domain_get ();
3152         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3153         MonoClass *field_class;
3154         MonoMethodMessage *msg;
3155         MonoArray *out_args;
3156         MonoObject *exc;
3157
3158         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3159
3160         field_class = mono_class_from_mono_type (field->type);
3161
3162         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3163                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
3164                 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
3165                 return;
3166         }
3167
3168         if (!setter) {
3169                 int i;
3170
3171                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
3172                         MonoMethod *cm = mono_defaults.object_class->methods [i];
3173                
3174                         if (!strcmp (cm->name, "FieldSetter")) {
3175                                 setter = cm;
3176                                 break;
3177                         }
3178                 }
3179                 g_assert (setter);
3180         }
3181
3182         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3183         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
3184
3185         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3186         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3187         mono_array_set (msg->args, gpointer, 2, arg);
3188
3189         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3190
3191         if (exc) mono_raise_exception ((MonoException *)exc);
3192 }
3193