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