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