2004-09-13 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mono / metadata / object.c
1 /*
2  * object.c: Object creation for the Mono runtime
3  *
4  * Author:
5  *   Miguel de Icaza (miguel@ximian.com)
6  *   Paolo Molaro (lupus@ximian.com)
7  *
8  * (C) 2001-2004 Ximian, Inc.
9  */
10 #include <config.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <signal.h>
14 #include <string.h>
15 #include <mono/metadata/mono-endian.h>
16 #include <mono/metadata/tabledefs.h>
17 #include <mono/metadata/tokentype.h>
18 #include <mono/metadata/loader.h>
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/gc-internal.h>
21 #include <mono/metadata/exception.h>
22 #include <mono/metadata/domain-internals.h>
23 #include "mono/metadata/metadata-internals.h"
24 #include "mono/metadata/class-internals.h"
25 #include <mono/metadata/assembly.h>
26 #include <mono/metadata/threadpool.h>
27 #include <mono/metadata/marshal.h>
28 #include "mono/metadata/debug-helpers.h"
29 #include "mono/metadata/marshal.h"
30 #include <mono/metadata/threads.h>
31 #include <mono/metadata/threads-types.h>
32 #include <mono/metadata/environment.h>
33 #include "mono/metadata/profiler-private.h"
34 #include <mono/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 int
1165 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, char *blob, void *value)
1166 {
1167         int retval = 0;
1168         const char *p = blob;
1169         mono_metadata_decode_blob_size (p, &p);
1170
1171         switch (type) {
1172         case MONO_TYPE_BOOLEAN:
1173         case MONO_TYPE_U1:
1174         case MONO_TYPE_I1:
1175                 *(guint8 *) value = *p;
1176                 break;
1177         case MONO_TYPE_CHAR:
1178         case MONO_TYPE_U2:
1179         case MONO_TYPE_I2:
1180                 *(guint16*) value = read16 (p);
1181                 break;
1182         case MONO_TYPE_U4:
1183         case MONO_TYPE_I4:
1184                 *(guint32*) value = read32 (p);
1185                 break;
1186         case MONO_TYPE_U8:
1187         case MONO_TYPE_I8:
1188                 *(guint64*) value = read64 (p);
1189                 break;
1190         case MONO_TYPE_R4:
1191                 readr4 (p, (float*) value);
1192                 break;
1193         case MONO_TYPE_R8:
1194                 readr8 (p, (double*) value);
1195                 break;
1196         case MONO_TYPE_STRING:
1197                 *(gpointer*) value = mono_ldstr_metdata_sig (domain, blob);
1198                 break;
1199         case MONO_TYPE_CLASS:
1200                 *(gpointer*) value = NULL;
1201                 break;
1202         default:
1203                 retval = -1;
1204                 g_warning ("type 0x%02x should not be in constant table", type);
1205         }
1206         return retval;
1207 }
1208
1209 static void
1210 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
1211 {
1212         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
1213         mono_get_constant_value_from_blob (domain, field->def_type, field->data, value);
1214 }
1215
1216
1217 void
1218 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
1219 {
1220         void *src;
1221
1222         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
1223         
1224         if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
1225                 get_default_field_value (vt->domain, field, value);
1226                 return;
1227         }
1228
1229         src = (char*)vt->data + field->offset;
1230         set_value (field->type, value, src, TRUE);
1231 }
1232
1233 void
1234 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
1235 {
1236         default_mono_runtime_invoke (prop->set, obj, params, exc);
1237 }
1238
1239 MonoObject*
1240 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
1241 {
1242         return default_mono_runtime_invoke (prop->get, obj, params, exc);
1243 }
1244
1245
1246 MonoMethod *
1247 mono_get_delegate_invoke (MonoClass *klass)
1248 {
1249         MonoMethod *im;
1250         int i;
1251
1252         im = NULL;
1253
1254         for (i = 0; i < klass->method.count; ++i) {
1255                 if (klass->methods [i]->name[0] == 'I' && 
1256                     !strcmp ("Invoke", klass->methods [i]->name)) {
1257                         im = klass->methods [i];
1258                 }
1259         }
1260
1261         g_assert (im);
1262
1263         return im;
1264 }
1265
1266 MonoObject*
1267 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
1268 {
1269         MonoMethod *im;
1270
1271         im = mono_get_delegate_invoke (delegate->vtable->klass);
1272         g_assert (im);
1273
1274         return mono_runtime_invoke (im, delegate, params, exc);
1275 }
1276
1277 static MonoArray* main_args;
1278
1279 MonoArray*
1280 mono_runtime_get_main_args (void)
1281 {
1282         return main_args;
1283 }
1284
1285 static void
1286 fire_process_exit_event (void)
1287 {
1288         MonoClassField *field;
1289         MonoDomain *domain = mono_domain_get ();
1290         gpointer pa [2];
1291         MonoObject *delegate, *exc;
1292         
1293         field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
1294         g_assert (field);
1295
1296         if (domain != mono_get_root_domain ())
1297                 return;
1298
1299         delegate = *(MonoObject **)(((char *)domain->domain) + field->offset); 
1300         if (delegate == NULL)
1301                 return;
1302
1303         pa [0] = domain;
1304         pa [1] = NULL;
1305         mono_runtime_delegate_invoke (delegate, pa, &exc);
1306 }
1307
1308 /*
1309  * Execute a standard Main() method (argc/argv contains the
1310  * executable name). This method also sets the command line argument value
1311  * needed by System.Environment.
1312  */
1313 int
1314 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
1315                        MonoObject **exc)
1316 {
1317         int i;
1318         MonoArray *args = NULL;
1319         MonoDomain *domain = mono_domain_get ();
1320         gchar *utf8_fullpath;
1321         int result;
1322
1323         main_thread = mono_thread_current ();
1324
1325         main_args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
1326
1327         if (!g_path_is_absolute (argv [0])) {
1328                 gchar *basename = g_path_get_basename (argv [0]);
1329                 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
1330                                                     basename,
1331                                                     NULL);
1332
1333                 utf8_fullpath = mono_utf8_from_external (fullpath);
1334                 if(utf8_fullpath == NULL) {
1335                         /* Printing the arg text will cause glib to
1336                          * whinge about "Invalid UTF-8", but at least
1337                          * its relevant, and shows the problem text
1338                          * string.
1339                          */
1340                         g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
1341                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1342                         exit (-1);
1343                 }
1344
1345                 g_free (fullpath);
1346                 g_free (basename);
1347         } else {
1348                 utf8_fullpath = mono_utf8_from_external (argv[0]);
1349                 if(utf8_fullpath == NULL) {
1350                         g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
1351                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1352                         exit (-1);
1353                 }
1354         }
1355                 
1356         mono_array_set (main_args, gpointer, 0, mono_string_new (domain, utf8_fullpath));
1357         g_free (utf8_fullpath);
1358
1359         for (i = 1; i < argc; ++i) {
1360                 gchar *utf8_arg;
1361                 MonoString *arg;
1362
1363                 utf8_arg=mono_utf8_from_external (argv[i]);
1364                 if(utf8_arg==NULL) {
1365                         /* Ditto the comment about Invalid UTF-8 here */
1366                         g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
1367                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1368                         exit (-1);
1369                 }
1370                 
1371                 arg = mono_string_new (domain, utf8_arg);
1372                 mono_array_set (main_args, gpointer, i, arg);
1373         }
1374         argc--;
1375         argv++;
1376         if (method->signature->param_count) {
1377                 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
1378                 for (i = 0; i < argc; ++i) {
1379                         /* The encodings should all work, given that
1380                          * we've checked all these args for the
1381                          * main_args array.
1382                          */
1383                         MonoString *arg = mono_string_new (domain, mono_utf8_from_external (argv [i]));
1384                         mono_array_set (args, gpointer, i, arg);
1385                 }
1386         } else {
1387                 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
1388         }
1389         
1390         mono_assembly_set_main (method->klass->image->assembly);
1391
1392         result = mono_runtime_exec_main (method, args, exc);
1393         fire_process_exit_event ();
1394         return result;
1395 }
1396
1397 /* Used in mono_unhandled_exception */
1398 static MonoObject *
1399 create_unhandled_exception_eventargs (MonoObject *exc)
1400 {
1401         MonoClass *klass;
1402         gpointer args [2];
1403         MonoMethod *method = NULL;
1404         MonoBoolean is_terminating = TRUE;
1405         MonoObject *obj;
1406         gint i;
1407
1408         klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
1409         g_assert (klass);
1410
1411         mono_class_init (klass);
1412
1413         /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
1414         for (i = 0; i < klass->method.count; ++i) {
1415                 method = klass->methods [i];
1416                 if (!strcmp (".ctor", method->name) &&
1417                     method->signature->param_count == 2 &&
1418                     method->flags & METHOD_ATTRIBUTE_PUBLIC)
1419                         break;
1420                 method = NULL;
1421         }
1422
1423         g_assert (method);
1424
1425         args [0] = exc;
1426         args [1] = &is_terminating;
1427
1428         obj = mono_object_new (mono_domain_get (), klass);
1429         mono_runtime_invoke (method, obj, args, NULL);
1430
1431         return obj;
1432 }
1433
1434 /*
1435  * We call this function when we detect an unhandled exception
1436  * in the default domain.
1437  * It invokes the * UnhandledException event in AppDomain or prints
1438  * a warning to the console 
1439  */
1440 void
1441 mono_unhandled_exception (MonoObject *exc)
1442 {
1443         MonoDomain *domain = mono_domain_get ();
1444         MonoClassField *field;
1445         MonoObject *delegate;
1446
1447         field=mono_class_get_field_from_name(mono_defaults.appdomain_class, 
1448                                              "UnhandledException");
1449         g_assert (field);
1450
1451         if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
1452                 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset); 
1453
1454                 /* set exitcode only in the main thread */
1455                 if (mono_thread_current () == main_thread)
1456                         mono_environment_exitcode_set (1);
1457                 if (domain != mono_get_root_domain () || !delegate) {
1458                         mono_print_unhandled_exception (exc);
1459                 } else {
1460                         MonoObject *e = NULL;
1461                         gpointer pa [2];
1462
1463                         pa [0] = domain->domain;
1464                         pa [1] = create_unhandled_exception_eventargs (exc);
1465                         mono_runtime_delegate_invoke (delegate, pa, &e);
1466                         
1467                         if (e) {
1468                                 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
1469                                 g_warning ("exception inside UnhandledException handler: %s\n", msg);
1470                                 g_free (msg);
1471                         }
1472                 }
1473         }
1474 }
1475
1476 /*
1477  * Launch a new thread to start all setup that requires managed code
1478  * to be executed.
1479  *
1480  * main_func is called back from the thread with main_args as the
1481  * parameter.  The callback function is expected to start Main()
1482  * eventually.  This function then waits for all managed threads to
1483  * finish.
1484  */
1485 void
1486 mono_runtime_exec_managed_code (MonoDomain *domain,
1487                                 MonoMainThreadFunc main_func,
1488                                 gpointer main_args)
1489 {
1490         mono_thread_create (domain, main_func, main_args);
1491
1492         mono_thread_manage ();
1493 }
1494
1495 /*
1496  * Execute a standard Main() method (args doesn't contain the
1497  * executable name).
1498  */
1499 int
1500 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
1501 {
1502         MonoDomain *domain;
1503         gpointer pa [1];
1504         int rval;
1505
1506         g_assert (args);
1507
1508         pa [0] = args;
1509
1510         domain = mono_object_domain (args);
1511         if (!domain->entry_assembly) {
1512                 gchar *str;
1513                 gchar *config_suffix;
1514                 MonoAssembly *assembly;
1515
1516                 assembly = method->klass->image->assembly;
1517                 domain->entry_assembly = assembly;
1518                 domain->setup->application_base = mono_string_new (domain, assembly->basedir);
1519
1520                 config_suffix = g_strconcat (assembly->aname.name, ".exe.config", NULL);
1521                 str = g_build_filename (assembly->basedir, config_suffix, NULL);
1522                 g_free (config_suffix);
1523                 domain->setup->configuration_file = mono_string_new (domain, str);
1524                 g_free (str);
1525         }
1526
1527         /* FIXME: check signature of method */
1528         if (method->signature->ret->type == MONO_TYPE_I4) {
1529                 MonoObject *res;
1530                 res = mono_runtime_invoke (method, NULL, pa, exc);
1531                 if (!exc || !*exc)
1532                         rval = *(guint32 *)((char *)res + sizeof (MonoObject));
1533                 else
1534                         rval = -1;
1535
1536                 mono_environment_exitcode_set (rval);
1537         } else {
1538                 mono_runtime_invoke (method, NULL, pa, exc);
1539                 if (!exc || !*exc)
1540                         rval = 0;
1541                 else {
1542                         /* If the return type of Main is void, only
1543                          * set the exitcode if an exception was thrown
1544                          * (we don't want to blow away an
1545                          * explicitly-set exit code)
1546                          */
1547                         rval = -1;
1548                         mono_environment_exitcode_set (rval);
1549                 }
1550         }
1551
1552         return rval;
1553 }
1554
1555 void
1556 mono_install_runtime_invoke (MonoInvokeFunc func)
1557 {
1558         default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
1559 }
1560
1561 /**
1562  * mono_runtime_invoke:
1563  *
1564  * Invokes the method represented by `method' on the object `obj'.
1565  *
1566  * obj is the 'this' pointer, it should be NULL for static
1567  * methods, a MonoObject* for object instances and a pointer to
1568  * the value type for value types.
1569  *
1570  * The params array contains the arguments to the method with the
1571  * same convention: MonoObject* pointers for object instances and
1572  * pointers to the value type otherwise. The _invoke_array
1573  * variant takes a C# object[] as the params argument (MonoArray
1574  * *params): in this case the value types are boxed inside the
1575  * respective reference representation.
1576  * 
1577  * From unmanaged code you'll usually use the
1578  * mono_runtime_invoke() variant.
1579  *
1580  * Note that this function doesn't handle virtual methods for
1581  * you, it will exec the exact method you pass: we still need to
1582  * expose a function to lookup the derived class implementation
1583  * of a virtual method (there are examples of this in the code,
1584  * though).
1585  * 
1586  * You can pass NULL as the exc argument if you don't want to
1587  * catch exceptions, otherwise, *exc will be set to the exception
1588  * thrown, if any.  if an exception is thrown, you can't use the
1589  * MonoObject* result from the function.
1590  * 
1591  * If the method returns a value type, it is boxed in an object
1592  * reference.
1593  */
1594 MonoObject*
1595 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
1596                            MonoObject **exc)
1597 {
1598         MonoMethodSignature *sig = method->signature;
1599         gpointer *pa = NULL;
1600         int i;
1601                 
1602         if (NULL != params) {
1603                 pa = alloca (sizeof (gpointer) * mono_array_length (params));
1604                 for (i = 0; i < mono_array_length (params); i++) {
1605                         if (sig->params [i]->byref) {
1606                                 /* nothing to do */
1607                         }
1608
1609                         switch (sig->params [i]->type) {
1610                         case MONO_TYPE_U1:
1611                         case MONO_TYPE_I1:
1612                         case MONO_TYPE_BOOLEAN:
1613                         case MONO_TYPE_U2:
1614                         case MONO_TYPE_I2:
1615                         case MONO_TYPE_CHAR:
1616                         case MONO_TYPE_U:
1617                         case MONO_TYPE_I:
1618                         case MONO_TYPE_U4:
1619                         case MONO_TYPE_I4:
1620                         case MONO_TYPE_U8:
1621                         case MONO_TYPE_I8:
1622                         case MONO_TYPE_R4:
1623                         case MONO_TYPE_R8:
1624                         case MONO_TYPE_VALUETYPE:
1625                                 /* MS seems to create the objects if a null is passed in */
1626                                 if (! ((gpointer *)params->vector)[i])
1627                                         ((gpointer*)params->vector)[i] = mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i]));
1628                                 pa [i] = (char *)(((gpointer *)params->vector)[i]) + sizeof (MonoObject);
1629                                 break;
1630                         case MONO_TYPE_STRING:
1631                         case MONO_TYPE_OBJECT:
1632                         case MONO_TYPE_CLASS:
1633                         case MONO_TYPE_ARRAY:
1634                         case MONO_TYPE_SZARRAY:
1635                                 if (sig->params [i]->byref)
1636                                         pa [i] = &(((gpointer *)params->vector)[i]);
1637                                 else
1638                                         pa [i] = (char *)(((gpointer *)params->vector)[i]);
1639                                 break;
1640                         default:
1641                                 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
1642                         }
1643                 }
1644         }
1645
1646         if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
1647                 void *o = obj;
1648                 if (!obj) {
1649                         obj = mono_object_new (mono_domain_get (), method->klass);
1650                         if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
1651                                 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
1652                         }
1653                         if (method->klass->valuetype)
1654                                 o = mono_object_unbox (obj);
1655                         else
1656                                 o = obj;
1657                 }
1658                 mono_runtime_invoke (method, o, pa, exc);
1659                 return obj;
1660         } else {
1661                 /* obj must be already unboxed if needed */
1662                 return mono_runtime_invoke (method, obj, pa, exc);
1663         }
1664 }
1665
1666 static void
1667 arith_overflow (void)
1668 {
1669         mono_raise_exception (mono_get_exception_overflow ());
1670 }
1671
1672 /**
1673  * mono_object_allocate:
1674  * @size: number of bytes to allocate
1675  *
1676  * This is a very simplistic routine until we have our GC-aware
1677  * memory allocator. 
1678  *
1679  * Returns: an allocated object of size @size, or NULL on failure.
1680  */
1681 static inline void *
1682 mono_object_allocate (size_t size)
1683 {
1684 #if HAVE_BOEHM_GC
1685         /* if this is changed to GC_debug_malloc(), we need to change also metadata/gc.c */
1686         void *o = GC_MALLOC (size);
1687 #else
1688         void *o = calloc (1, size);
1689         if (!o)
1690                 return mono_gc_out_of_memory (size);
1691 #endif
1692         mono_stats.new_object_count++;
1693
1694         return o;
1695 }
1696
1697 #if CREATION_SPEEDUP
1698 static inline void *
1699 mono_object_allocate_spec (size_t size, void *gcdescr)
1700 {
1701         /* if this is changed to GC_debug_malloc(), we need to change also metadata/gc.c */
1702         void *o = GC_GCJ_MALLOC (size, gcdescr);
1703         mono_stats.new_object_count++;
1704
1705         return o;
1706 }
1707 #endif
1708
1709 /**
1710  * mono_object_new:
1711  * @klass: the class of the object that we want to create
1712  *
1713  * Returns a newly created object whose definition is
1714  * looked up using @klass.   This will not invoke any constructors, 
1715  * so the consumer of this routine has to invoke any constructors on
1716  * its own to initialize the object.
1717  */
1718 MonoObject *
1719 mono_object_new (MonoDomain *domain, MonoClass *klass)
1720 {
1721         MONO_ARCH_SAVE_REGS;
1722         return mono_object_new_specific (mono_class_vtable (domain, klass));
1723 }
1724
1725 /**
1726  * mono_object_new_specific:
1727  * @vtable: the vtable of the object that we want to create
1728  *
1729  * Returns: A newly created object with class and domain specified
1730  * by @vtable
1731  */
1732 MonoObject *
1733 mono_object_new_specific (MonoVTable *vtable)
1734 {
1735         MonoObject *o;
1736
1737         MONO_ARCH_SAVE_REGS;
1738         
1739         if (vtable->remote)
1740         {
1741                 gpointer pa [1];
1742                 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
1743
1744                 if (im == NULL) {
1745                         MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
1746                         int i;
1747
1748                         if (!klass->inited)
1749                                 mono_class_init (klass);
1750
1751                         for (i = 0; i < klass->method.count; ++i) {
1752                                 if (!strcmp ("CreateProxyForType", klass->methods [i]->name) &&
1753                                         klass->methods [i]->signature->param_count == 1) {
1754                                         im = klass->methods [i];
1755                                         break;
1756                                 }
1757                         }
1758                         g_assert (im);
1759                         vtable->domain->create_proxy_for_type_method = im;
1760                 }
1761         
1762                 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
1763
1764                 o = mono_runtime_invoke (im, NULL, pa, NULL);           
1765                 if (o != NULL) return o;
1766         }
1767
1768         return mono_object_new_alloc_specific (vtable);
1769 }
1770
1771 MonoObject *
1772 mono_object_new_alloc_specific (MonoVTable *vtable)
1773 {
1774         MonoObject *o;
1775
1776 #if CREATION_SPEEDUP
1777         if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
1778                 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
1779         } else {
1780 /*              printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
1781                 o = mono_object_allocate (vtable->klass->instance_size);
1782                 o->vtable = vtable;
1783         }
1784 #else
1785         o = mono_object_allocate (vtable->klass->instance_size);
1786         o->vtable = vtable;
1787 #endif
1788         if (vtable->klass->has_finalize)
1789                 mono_object_register_finalizer (o);
1790         
1791         mono_profiler_allocation (o, vtable->klass);
1792         return o;
1793 }
1794
1795 #if CREATION_SPEEDUP
1796
1797 MonoObject*
1798 mono_object_new_fast (MonoVTable *vtable)
1799 {
1800         return GC_GCJ_MALLOC (vtable->klass->instance_size, vtable);
1801 }
1802
1803 #endif
1804
1805 /*
1806  * Return the allocation function appropriate for the given class.
1807  */
1808
1809 void*
1810 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean *pass_size_in_words)
1811 {
1812         *pass_size_in_words = FALSE;
1813
1814         if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
1815                 return mono_object_new_specific;
1816
1817 #if CREATION_SPEEDUP
1818         if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
1819
1820                 return mono_object_new_fast;
1821
1822                 /* 
1823                  * FIXME: This is actually slower than mono_object_new_fast, because
1824                  * of the overhead of parameter passing.
1825                  */
1826                 /*
1827                 *pass_size_in_words = TRUE;
1828 #ifdef GC_REDIRECT_TO_LOCAL
1829                 return GC_local_gcj_fast_malloc;
1830 #else
1831                 return GC_gcj_fast_malloc;
1832 #endif
1833                 */
1834         }
1835 #endif
1836
1837         return mono_object_new_specific;
1838 }
1839
1840 /**
1841  * mono_object_new_from_token:
1842  * @image: Context where the type_token is hosted
1843  * @token: a token of the type that we want to create
1844  *
1845  * Returns: A newly created object whose definition is
1846  * looked up using @token in the @image image
1847  */
1848 MonoObject *
1849 mono_object_new_from_token  (MonoDomain *domain, MonoImage *image, guint32 token)
1850 {
1851         MonoClass *class;
1852
1853         class = mono_class_get (image, token);
1854
1855         return mono_object_new (domain, class);
1856 }
1857
1858
1859 /**
1860  * mono_object_clone:
1861  * @obj: the object to clone
1862  *
1863  * Returns: A newly created object who is a shallow copy of @obj
1864  */
1865 MonoObject *
1866 mono_object_clone (MonoObject *obj)
1867 {
1868         MonoObject *o;
1869         int size;
1870
1871         size = obj->vtable->klass->instance_size;
1872         o = mono_object_allocate (size);
1873         mono_profiler_allocation (o, obj->vtable->klass);
1874
1875         memcpy (o, obj, size);
1876
1877         if (obj->vtable->klass->has_finalize)
1878                 mono_object_register_finalizer (o);
1879         return o;
1880 }
1881
1882 /**
1883  * mono_array_clone:
1884  * @array: the array to clone
1885  *
1886  * Returns: A newly created array who is a shallow copy of @array
1887  */
1888 MonoArray*
1889 mono_array_clone (MonoArray *array)
1890 {
1891         MonoArray *o;
1892         int size, i;
1893         guint32 *sizes;
1894         MonoClass *klass = array->obj.vtable->klass;
1895
1896         MONO_ARCH_SAVE_REGS;
1897
1898         if (array->bounds == NULL) {
1899                 size = mono_array_length (array);
1900                 o = mono_array_new_full (((MonoObject *)array)->vtable->domain,
1901                                          klass, &size, NULL);
1902
1903                 size *= mono_array_element_size (klass);
1904                 memcpy (o, array, sizeof (MonoArray) + size);
1905
1906                 return o;
1907         }
1908         
1909         sizes = alloca (klass->rank * sizeof(guint32) * 2);
1910         size = mono_array_element_size (klass);
1911         for (i = 0; i < klass->rank; ++i) {
1912                 sizes [i] = array->bounds [i].length;
1913                 size *= array->bounds [i].length;
1914                 sizes [i + klass->rank] = array->bounds [i].lower_bound;
1915         }
1916         o = mono_array_new_full (((MonoObject *)array)->vtable->domain, 
1917                                  klass, sizes, sizes + klass->rank);
1918         memcpy (o, array, sizeof(MonoArray) + size);
1919
1920         return o;
1921 }
1922
1923 /* helper macros to check for overflow when calculating the size of arrays */
1924 #define MYGUINT32_MAX 4294967295U
1925 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1926         (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
1927 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1928         ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1929         (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
1930
1931 /*
1932  * mono_array_new_full:
1933  * @domain: domain where the object is created
1934  * @array_class: array class
1935  * @lengths: lengths for each dimension in the array
1936  * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
1937  *
1938  * This routine creates a new array objects with the given dimensions,
1939  * lower bounds and type.
1940  */
1941 MonoArray*
1942 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, 
1943                      guint32 *lengths, guint32 *lower_bounds)
1944 {
1945         guint32 byte_len, len;
1946         MonoObject *o;
1947         MonoArray *array;
1948         MonoArrayBounds *bounds;
1949         MonoVTable *vtable;
1950         int i;
1951
1952         if (!array_class->inited)
1953                 mono_class_init (array_class);
1954
1955         byte_len = mono_array_element_size (array_class);
1956         len = 1;
1957
1958         if (array_class->rank == 1 &&
1959             (lower_bounds == NULL || lower_bounds [0] == 0)) {
1960                 bounds = NULL;
1961                 len = lengths [0];
1962                 if ((int) len < 0)
1963                         arith_overflow ();
1964         } else {
1965         #if HAVE_BOEHM_GC
1966                 bounds = GC_MALLOC (sizeof (MonoArrayBounds) * array_class->rank);
1967         #else
1968                 bounds = g_malloc0 (sizeof (MonoArrayBounds) * array_class->rank);
1969         #endif
1970                 for (i = 0; i < array_class->rank; ++i)
1971                         if ((int) lengths [i] < 0)
1972                                 arith_overflow ();
1973                 
1974                 for (i = 0; i < array_class->rank; ++i) {
1975                         bounds [i].length = lengths [i];
1976                         if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
1977                                 mono_gc_out_of_memory (MYGUINT32_MAX);
1978                         len *= lengths [i];
1979                 }
1980
1981                 if (lower_bounds)
1982                         for (i = 0; i < array_class->rank; ++i)
1983                                 bounds [i].lower_bound = lower_bounds [i];
1984         }
1985
1986         if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
1987                 mono_gc_out_of_memory (MYGUINT32_MAX);
1988         byte_len *= len;
1989         if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
1990                 mono_gc_out_of_memory (MYGUINT32_MAX);
1991         byte_len += sizeof (MonoArray);
1992         /* 
1993          * Following three lines almost taken from mono_object_new ():
1994          * they need to be kept in sync.
1995          */
1996         vtable = mono_class_vtable (domain, array_class);
1997 #if CREATION_SPEEDUP
1998         if (vtable->gc_descr != GC_NO_DESCRIPTOR)
1999                 o = mono_object_allocate_spec (byte_len, vtable);
2000         else {
2001                 o = mono_object_allocate (byte_len);
2002                 o->vtable = vtable;
2003         }
2004 #else
2005         o = mono_object_allocate (byte_len);
2006         o->vtable = vtable;
2007 #endif
2008
2009         array = (MonoArray*)o;
2010
2011         array->bounds = bounds;
2012         array->max_length = len;
2013
2014         mono_profiler_allocation (o, array_class);
2015
2016         return array;
2017 }
2018
2019 /*
2020  * mono_array_new:
2021  * @domain: domain where the object is created
2022  * @eclass: element class
2023  * @n: number of array elements
2024  *
2025  * This routine creates a new szarray with @n elements of type @eclass.
2026  */
2027 MonoArray *
2028 mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
2029 {
2030         MonoClass *ac;
2031
2032         MONO_ARCH_SAVE_REGS;
2033
2034         ac = mono_array_class_get (eclass, 1);
2035         g_assert (ac != NULL);
2036
2037         return mono_array_new_specific (mono_class_vtable (domain, ac), n);
2038 }
2039
2040 /*
2041  * mono_array_new_specific:
2042  * @vtable: a vtable in the appropriate domain for an initialized class
2043  * @n: number of array elements
2044  *
2045  * This routine is a fast alternative to mono_array_new() for code which
2046  * can be sure about the domain it operates in.
2047  */
2048 MonoArray *
2049 mono_array_new_specific (MonoVTable *vtable, guint32 n)
2050 {
2051         MonoObject *o;
2052         MonoArray *ao;
2053         guint32 byte_len, elem_size;
2054
2055         MONO_ARCH_SAVE_REGS;
2056
2057         if ((int) n < 0)
2058                 arith_overflow ();
2059         
2060         elem_size = mono_array_element_size (vtable->klass);
2061         if (CHECK_MUL_OVERFLOW_UN (n, elem_size))
2062                 mono_gc_out_of_memory (MYGUINT32_MAX);
2063         byte_len = n * elem_size;
2064         if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
2065                 mono_gc_out_of_memory (MYGUINT32_MAX);
2066         byte_len += sizeof (MonoArray);
2067 #if CREATION_SPEEDUP
2068         if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2069                 o = mono_object_allocate_spec (byte_len, vtable);
2070         } else {
2071 /*              printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
2072                 o = mono_object_allocate (byte_len);
2073                 o->vtable = vtable;
2074         }
2075 #else
2076         o = mono_object_allocate (byte_len);
2077         o->vtable = vtable;
2078 #endif
2079
2080         ao = (MonoArray *)o;
2081         ao->bounds = NULL;
2082         ao->max_length = n;
2083         mono_profiler_allocation (o, vtable->klass);
2084
2085         return ao;
2086 }
2087
2088 /**
2089  * mono_string_new_utf16:
2090  * @text: a pointer to an utf16 string
2091  * @len: the length of the string
2092  *
2093  * Returns: A newly created string object which contains @text.
2094  */
2095 MonoString *
2096 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
2097 {
2098         MonoString *s;
2099         
2100         s = mono_string_new_size (domain, len);
2101         g_assert (s != NULL);
2102
2103         memcpy (mono_string_chars (s), text, len * 2);
2104
2105         return s;
2106 }
2107
2108 /**
2109  * mono_string_new_size:
2110  * @text: a pointer to an utf16 string
2111  * @len: the length of the string
2112  *
2113  * Returns: A newly created string object of @len
2114  */
2115 MonoString *
2116 mono_string_new_size (MonoDomain *domain, gint32 len)
2117 {
2118         MonoString *s;
2119         MonoVTable *vtable;
2120         size_t size = (sizeof (MonoString) + ((len + 1) * 2));
2121
2122         /* overflow ? can't fit it, can't allocate it! */
2123         if (len > size)
2124                 mono_gc_out_of_memory (-1);
2125
2126         vtable = mono_class_vtable (domain, mono_defaults.string_class);
2127
2128 #if CREATION_SPEEDUP
2129         if (vtable->gc_descr != GC_NO_DESCRIPTOR)
2130                 s = mono_object_allocate_spec (size, vtable);
2131         else {
2132                 s = (MonoString*)mono_object_allocate (size);
2133                 s->object.vtable = vtable;
2134         }
2135 #else
2136         s = (MonoString*)mono_object_allocate (size);
2137         s->object.vtable = vtable;
2138 #endif
2139
2140         s->length = len;
2141         mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
2142
2143         return s;
2144 }
2145
2146 /*
2147  * mono_string_new_len:
2148  * @text: a pointer to an utf8 string
2149  * @length: number of bytes in @text to consider
2150  *
2151  * Returns: A newly created string object which contains @text.
2152  */
2153 MonoString*
2154 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
2155 {
2156         GError *error = NULL;
2157         MonoString *o = NULL;
2158         guint16 *ut;
2159         glong items_written;
2160
2161         ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
2162
2163         if (!error)
2164                 o = mono_string_new_utf16 (domain, ut, items_written);
2165         else 
2166                 g_error_free (error);
2167
2168         g_free (ut);
2169
2170         return o;
2171 }
2172
2173 /**
2174  * mono_string_new:
2175  * @text: a pointer to an utf8 string
2176  *
2177  * Returns: A newly created string object which contains @text.
2178  */
2179 MonoString*
2180 mono_string_new (MonoDomain *domain, const char *text)
2181 {
2182         GError *error = NULL;
2183         MonoString *o = NULL;
2184         guint16 *ut;
2185         glong items_written;
2186         int l;
2187
2188         l = strlen (text);
2189         
2190         ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
2191
2192         if (!error)
2193                 o = mono_string_new_utf16 (domain, ut, items_written);
2194         else 
2195                 g_error_free (error);
2196
2197         g_free (ut);
2198
2199         return o;
2200 }
2201
2202 /*
2203  * mono_string_new_wrapper:
2204  * @text: pointer to utf8 characters.
2205  *
2206  * Helper function to create a string object from @text in the current domain.
2207  */
2208 MonoString*
2209 mono_string_new_wrapper (const char *text)
2210 {
2211         MonoDomain *domain = mono_domain_get ();
2212
2213         MONO_ARCH_SAVE_REGS;
2214
2215         if (text)
2216                 return mono_string_new (domain, text);
2217
2218         return NULL;
2219 }
2220
2221 /**
2222  * mono_value_box:
2223  * @class: the class of the value
2224  * @value: a pointer to the unboxed data
2225  *
2226  * Returns: A newly created object which contains @value.
2227  */
2228 MonoObject *
2229 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
2230 {
2231         MonoObject *res;
2232         int size;
2233         MonoVTable *vtable;
2234
2235         g_assert (class->valuetype);
2236
2237         vtable = mono_class_vtable (domain, class);
2238         size = mono_class_instance_size (class);
2239         res = mono_object_allocate (size);
2240         res->vtable = vtable;
2241         mono_profiler_allocation (res, class);
2242
2243         size = size - sizeof (MonoObject);
2244
2245 #if NO_UNALIGNED_ACCESS
2246         memcpy ((char *)res + sizeof (MonoObject), value, size);
2247 #else
2248         switch (size) {
2249         case 1:
2250                 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
2251                 break;
2252         case 2:
2253                 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
2254                 break;
2255         case 4:
2256                 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
2257                 break;
2258         case 8:
2259                 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
2260                 break;
2261         default:
2262                 memcpy ((char *)res + sizeof (MonoObject), value, size);
2263         }
2264 #endif
2265         if (class->has_finalize)
2266                 mono_object_register_finalizer (res);
2267         return res;
2268 }
2269
2270 MonoDomain*
2271 mono_object_get_domain (MonoObject *obj)
2272 {
2273         return mono_object_domain (obj);
2274 }
2275
2276 MonoClass*
2277 mono_object_get_class (MonoObject *obj)
2278 {
2279         return mono_object_class (obj);
2280 }
2281
2282 gpointer
2283 mono_object_unbox (MonoObject *obj)
2284 {
2285         /* add assert for valuetypes? */
2286         g_assert (obj->vtable->klass->valuetype);
2287         return ((char*)obj) + sizeof (MonoObject);
2288 }
2289
2290 /**
2291  * mono_object_isinst:
2292  * @obj: an object
2293  * @klass: a pointer to a class 
2294  *
2295  * Returns: @obj if @obj is derived from @klass
2296  */
2297 MonoObject *
2298 mono_object_isinst (MonoObject *obj, MonoClass *klass)
2299 {
2300         if (!klass->inited)
2301                 mono_class_init (klass);
2302
2303         if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) 
2304                 return mono_object_isinst_mbyref (obj, klass);
2305
2306         if (!obj)
2307                 return NULL;
2308
2309         return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
2310 }
2311
2312 MonoObject *
2313 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
2314 {
2315         MonoVTable *vt;
2316
2317         if (!obj)
2318                 return NULL;
2319
2320         vt = obj->vtable;
2321         
2322         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2323                 if ((klass->interface_id <= vt->max_interface_id) &&
2324                     (vt->interface_offsets [klass->interface_id] != 0))
2325                         return obj;
2326         }
2327         else {
2328                 MonoClass *oklass = vt->klass;
2329                 if ((oklass == mono_defaults.transparent_proxy_class))
2330                         oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2331         
2332                 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
2333                         return obj;
2334         }
2335
2336         if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info) 
2337         {
2338                 MonoDomain *domain = mono_domain_get ();
2339                 MonoObject *res;
2340                 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
2341                 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
2342                 MonoMethod *im = NULL;
2343                 gpointer pa [2];
2344                 int i;
2345         
2346                 for (i = 0; i < rpklass->method.count; ++i) {
2347                         if (!strcmp ("CanCastTo", rpklass->methods [i]->name)) {
2348                                 im = rpklass->methods [i];
2349                                 break;
2350                         }
2351                 }
2352         
2353                 im = mono_object_get_virtual_method (rp, im);
2354                 g_assert (im);
2355         
2356                 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
2357                 pa [1] = obj;
2358
2359                 res = mono_runtime_invoke (im, rp, pa, NULL);
2360         
2361                 if (*(MonoBoolean *) mono_object_unbox(res)) {
2362                         /* Update the vtable of the remote type, so it can safely cast to this new type */
2363                         mono_upgrade_remote_class (domain, ((MonoTransparentProxy *)obj)->remote_class, klass);
2364                         obj->vtable = ((MonoTransparentProxy *)obj)->remote_class->vtable;
2365                         return obj;
2366                 }
2367         }
2368
2369         return NULL;
2370 }
2371
2372 /**
2373  * mono_object_castclass_mbyref:
2374  * @obj: an object
2375  * @klass: a pointer to a class 
2376  *
2377  * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
2378  */
2379 MonoObject *
2380 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
2381 {
2382         if (!obj) return NULL;
2383         if (mono_object_isinst_mbyref (obj, klass)) return obj;
2384                 
2385         mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
2386                                                         "System",
2387                                                         "InvalidCastException"));
2388         return NULL;
2389 }
2390
2391 typedef struct {
2392         MonoDomain *orig_domain;
2393         char *ins;
2394         MonoString *res;
2395 } LDStrInfo;
2396
2397 static void
2398 str_lookup (MonoDomain *domain, gpointer user_data)
2399 {
2400         LDStrInfo *info = user_data;
2401         if (info->res || domain == info->orig_domain)
2402                 return;
2403         mono_domain_lock (domain);
2404         info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
2405         mono_domain_unlock (domain);
2406 }
2407
2408 static MonoString*
2409 mono_string_is_interned_lookup (MonoString *str, int insert)
2410 {
2411         MonoGHashTable *ldstr_table;
2412         MonoString *res;
2413         MonoDomain *domain;
2414         char *ins = g_malloc (4 + str->length * 2);
2415         char *p;
2416         
2417         /* Encode the length */
2418         /* Same code as in mono_image_insert_string () */
2419         p = ins;
2420         mono_metadata_encode_value (1 | (2 * str->length), p, &p);
2421
2422         /*
2423          * ins is stored in the hash table as a key and needs to have the same
2424          * representation as in the metadata: we swap the character bytes on big
2425          * endian boxes.
2426          */
2427 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
2428         {
2429                 int i;
2430                 char *p2 = (char *)mono_string_chars (str);
2431                 for (i = 0; i < str->length; ++i) {
2432                         *p++ = p2 [1];
2433                         *p++ = p2 [0];
2434                         p2 += 2;
2435                 }
2436         }
2437 #else
2438         memcpy (p, mono_string_chars (str), str->length * 2);
2439 #endif
2440         domain = ((MonoObject *)str)->vtable->domain;
2441         ldstr_table = domain->ldstr_table;
2442         mono_domain_lock (domain);
2443         if ((res = mono_g_hash_table_lookup (ldstr_table, ins))) {
2444                 mono_domain_unlock (domain);
2445                 g_free (ins);
2446                 return res;
2447         }
2448         if (insert) {
2449                 mono_g_hash_table_insert (ldstr_table, ins, str);
2450                 mono_domain_unlock (domain);
2451                 return str;
2452         } else {
2453                 LDStrInfo ldstr_info;
2454                 ldstr_info.orig_domain = domain;
2455                 ldstr_info.ins = ins;
2456                 ldstr_info.res = NULL;
2457
2458                 mono_domain_foreach (str_lookup, &ldstr_info);
2459                 if (ldstr_info.res) {
2460                         /* 
2461                          * the string was already interned in some other domain:
2462                          * intern it in the current one as well.
2463                          */
2464                         mono_g_hash_table_insert (ldstr_table, ins, str);
2465                         mono_domain_unlock (domain);
2466                         return str;
2467                 }
2468         }
2469         mono_domain_unlock (domain);
2470         g_free (ins);
2471         return NULL;
2472 }
2473
2474 MonoString*
2475 mono_string_is_interned (MonoString *o)
2476 {
2477         return mono_string_is_interned_lookup (o, FALSE);
2478 }
2479
2480 MonoString*
2481 mono_string_intern (MonoString *str)
2482 {
2483         return mono_string_is_interned_lookup (str, TRUE);
2484 }
2485
2486 /*
2487  * mono_ldstr:
2488  * @domain: the domain where the string will be used.
2489  * @image: a metadata context
2490  * @idx: index into the user string table.
2491  * 
2492  * Implementation for the ldstr opcode.
2493  */
2494 MonoString*
2495 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
2496 {
2497         MONO_ARCH_SAVE_REGS;
2498
2499         if (image->dynamic)
2500                 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx);
2501         else
2502                 return mono_ldstr_metdata_sig (domain, mono_metadata_user_string (image, idx));
2503 }
2504
2505 /*
2506  * mono_ldstr_metdata_sig
2507  * @domain: the domain for the string
2508  * @sig: the signature of a metadata string
2509  *
2510  * returns a MonoString for a string stored in the metadata
2511  */
2512 static MonoString*
2513 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig)
2514 {
2515         const char *str = sig;
2516         MonoString *o;
2517         size_t len2;
2518         
2519         mono_domain_lock (domain);
2520         if ((o = mono_g_hash_table_lookup (domain->ldstr_table, sig))) {
2521                 mono_domain_unlock (domain);
2522                 return o;
2523         }
2524         
2525         len2 = mono_metadata_decode_blob_size (str, &str);
2526         len2 >>= 1;
2527
2528         o = mono_string_new_utf16 (domain, (guint16*)str, len2);
2529 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
2530         {
2531                 int i;
2532                 guint16 *p2 = (guint16*)mono_string_chars (o);
2533                 for (i = 0; i < len2; ++i) {
2534                         *p2 = GUINT16_FROM_LE (*p2);
2535                         ++p2;
2536                 }
2537         }
2538 #endif
2539         mono_g_hash_table_insert (domain->ldstr_table, (gpointer)sig, o);
2540         mono_domain_unlock (domain);
2541
2542         return o;
2543 }
2544
2545 /*
2546  * mono_string_to_utf8:
2547  * @s: a System.String
2548  *
2549  * Return the UTF8 representation for @s.
2550  * the resulting buffer nedds to be freed with g_free().
2551  */
2552 char *
2553 mono_string_to_utf8 (MonoString *s)
2554 {
2555         char *as;
2556         GError *error = NULL;
2557
2558         if (s == NULL)
2559                 return NULL;
2560
2561         if (!s->length)
2562                 return g_strdup ("");
2563
2564         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, NULL, &error);
2565         if (error) {
2566                 g_warning (error->message);
2567                 g_error_free (error);
2568         }
2569
2570         return as;
2571 }
2572
2573 /*
2574  * mono_string_to_utf16:
2575  * @s: a MonoString
2576  *
2577  * Return an null-terminated array of the utf-16 chars
2578  * contained in @s. The result must be freed with g_free().
2579  * This is a temporary helper until our string implementation
2580  * is reworked to always include the null terminating char.
2581  */
2582 gunichar2 *
2583 mono_string_to_utf16 (MonoString *s)
2584 {
2585         char *as;
2586
2587         if (s == NULL)
2588                 return NULL;
2589
2590         as = g_malloc ((s->length * 2) + 2);
2591         as [(s->length * 2)] = '\0';
2592         as [(s->length * 2) + 1] = '\0';
2593
2594         if (!s->length) {
2595                 return (gunichar2 *)(as);
2596         }
2597         
2598         memcpy (as, mono_string_chars(s), s->length * 2);
2599         return (gunichar2 *)(as);
2600 }
2601
2602 /*
2603  * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString
2604  */
2605 MonoString *
2606 mono_string_from_utf16 (gunichar2 *data)
2607 {
2608         MonoDomain *domain = mono_domain_get ();
2609         int len = 0;
2610
2611         if (!data)
2612                 return NULL;
2613
2614         while (data [len]) len++;
2615
2616         return mono_string_new_utf16 (domain, data, len);
2617 }
2618
2619 static void
2620 default_ex_handler (MonoException *ex)
2621 {
2622         MonoObject *o = (MonoObject*)ex;
2623         g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
2624         exit (1);
2625 }
2626
2627 static MonoExceptionFunc ex_handler = default_ex_handler;
2628
2629 void
2630 mono_install_handler        (MonoExceptionFunc func)
2631 {
2632         ex_handler = func? func: default_ex_handler;
2633 }
2634
2635 /*
2636  * mono_raise_exception:
2637  * @ex: exception object
2638  *
2639  * Signal the runtime that the exception @ex has been raised in unmanaged code.
2640  */
2641 void
2642 mono_raise_exception (MonoException *ex) 
2643 {
2644         /*
2645          * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
2646          * that will cause gcc to omit the function epilog, causing problems when
2647          * the JIT tries to walk the stack, since the return address on the stack
2648          * will point into the next function in the executable, not this one.
2649          */
2650
2651         ex_handler (ex);
2652 }
2653
2654 MonoWaitHandle *
2655 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
2656 {
2657         MonoWaitHandle *res;
2658
2659         res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
2660
2661         res->handle = handle;
2662
2663         return res;
2664 }
2665
2666 MonoAsyncResult *
2667 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data)
2668 {
2669         MonoAsyncResult *res;
2670
2671         res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
2672
2673         res->data = data;
2674         res->async_state = state;
2675         if (handle != NULL)
2676                 res->handle = (MonoObject *) mono_wait_handle_new (domain, handle);
2677
2678         res->sync_completed = FALSE;
2679         res->completed = FALSE;
2680
2681         return res;
2682 }
2683
2684 void
2685 mono_message_init (MonoDomain *domain,
2686                    MonoMethodMessage *this, 
2687                    MonoReflectionMethod *method,
2688                    MonoArray *out_args)
2689 {
2690         MonoMethodSignature *sig = method->method->signature;
2691         MonoString *name;
2692         int i, j;
2693         char **names;
2694         guint8 arg_type;
2695
2696         this->method = method;
2697
2698         this->args = mono_array_new (domain, mono_defaults.object_class, sig->param_count);
2699         this->arg_types = mono_array_new (domain, mono_defaults.byte_class, sig->param_count);
2700         this->async_result = NULL;
2701         this->call_type = CallType_Sync;
2702
2703         names = g_new (char *, sig->param_count);
2704         mono_method_get_param_names (method->method, (const char **) names);
2705         this->names = mono_array_new (domain, mono_defaults.string_class, sig->param_count);
2706         
2707         for (i = 0; i < sig->param_count; i++) {
2708                  name = mono_string_new (domain, names [i]);
2709                  mono_array_set (this->names, gpointer, i, name);       
2710         }
2711
2712         g_free (names);
2713         for (i = 0, j = 0; i < sig->param_count; i++) {
2714
2715                 if (sig->params [i]->byref) {
2716                         if (out_args) {
2717                                 gpointer arg = mono_array_get (out_args, gpointer, j);
2718                                 mono_array_set (this->args, gpointer, i, arg);
2719                                 j++;
2720                         }
2721                         arg_type = 2;
2722                         if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
2723                                 arg_type |= 1;
2724                 } else {
2725                         arg_type = 1;
2726                 }
2727                 mono_array_set (this->arg_types, guint8, i, arg_type);
2728         }
2729 }
2730
2731 /**
2732  * mono_remoting_invoke:
2733  * @real_proxy: pointer to a RealProxy object
2734  * @msg: The MonoMethodMessage to execute
2735  * @exc: used to store exceptions
2736  * @out_args: used to store output arguments
2737  *
2738  * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
2739  * IMessage interface and it is not trivial to extract results from there. So
2740  * we call an helper method PrivateInvoke instead of calling
2741  * RealProxy::Invoke() directly.
2742  *
2743  * Returns: the result object.
2744  */
2745 MonoObject *
2746 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, 
2747                       MonoObject **exc, MonoArray **out_args)
2748 {
2749         MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
2750         gpointer pa [4];
2751
2752         /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
2753
2754         if (!im) {
2755                 MonoClass *klass;
2756                 int i;
2757
2758                 klass = mono_defaults.real_proxy_class; 
2759                        
2760                 for (i = 0; i < klass->method.count; ++i) {
2761                         if (!strcmp ("PrivateInvoke", klass->methods [i]->name) &&
2762                             klass->methods [i]->signature->param_count == 4) {
2763                                 im = klass->methods [i];
2764                                 break;
2765                         }
2766                 }
2767         
2768                 g_assert (im);
2769                 real_proxy->vtable->domain->private_invoke_method = im;
2770         }
2771
2772         pa [0] = real_proxy;
2773         pa [1] = msg;
2774         pa [2] = exc;
2775         pa [3] = out_args;
2776
2777         return mono_runtime_invoke (im, NULL, pa, exc);
2778 }
2779
2780 MonoObject *
2781 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
2782                      MonoObject **exc, MonoArray **out_args) 
2783 {
2784         MonoDomain *domain; 
2785         MonoMethod *method;
2786         MonoMethodSignature *sig;
2787         MonoObject *ret;
2788         int i, j, outarg_count = 0;
2789
2790         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
2791
2792                 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
2793                 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
2794                         target = tp->rp->unwrapped_server;
2795                 } else {
2796                         return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
2797                 }
2798         }
2799
2800         domain = mono_domain_get (); 
2801         method = msg->method->method;
2802         sig = method->signature;
2803
2804         for (i = 0; i < sig->param_count; i++) {
2805                 if (sig->params [i]->byref) 
2806                         outarg_count++;
2807         }
2808
2809         *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
2810         *exc = NULL;
2811
2812         ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
2813
2814         for (i = 0, j = 0; i < sig->param_count; i++) {
2815                 if (sig->params [i]->byref) {
2816                         gpointer arg;
2817                         arg = mono_array_get (msg->args, gpointer, i);
2818                         mono_array_set (*out_args, gpointer, j, arg);
2819                         j++;
2820                 }
2821         }
2822
2823         return ret;
2824 }
2825
2826 void
2827 mono_print_unhandled_exception (MonoObject *exc)
2828 {
2829         char *message = (char *) "";
2830         MonoString *str; 
2831         MonoMethod *method;
2832         MonoClass *klass;
2833         gboolean free_message = FALSE;
2834         gint i;
2835
2836         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
2837                 klass = exc->vtable->klass;
2838                 method = NULL;
2839                 while (klass && method == NULL) {
2840                         for (i = 0; i < klass->method.count; ++i) {
2841                                 method = klass->methods [i];
2842                                 if (!strcmp ("ToString", method->name) &&
2843                                     method->signature->param_count == 0 &&
2844                                     method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
2845                                     method->flags & METHOD_ATTRIBUTE_PUBLIC) {
2846                                         break;
2847                                 }
2848                                 method = NULL;
2849                         }
2850                         
2851                         if (method == NULL)
2852                                 klass = klass->parent;
2853                 }
2854
2855                 g_assert (method);
2856
2857                 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
2858                 if (str) {
2859                         message = mono_string_to_utf8 (str);
2860                         free_message = TRUE;
2861                 }
2862         }                               
2863
2864         /*
2865          * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space, 
2866          *         exc->vtable->klass->name, message);
2867          */
2868         g_printerr ("\nUnhandled Exception: %s\n", message);
2869         
2870         if (free_message)
2871                 g_free (message);
2872 }
2873
2874 /**
2875  * mono_delegate_ctor:
2876  * @this: pointer to an uninitialized delegate object
2877  * @target: target object
2878  * @addr: pointer to native code
2879  *
2880  * This is used to initialize a delegate. We also insert the method_info if
2881  * we find the info with mono_jit_info_table_find().
2882  */
2883 void
2884 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
2885 {
2886         MonoDomain *domain = mono_domain_get ();
2887         MonoDelegate *delegate = (MonoDelegate *)this;
2888         MonoMethod *method = NULL;
2889         MonoClass *class;
2890         MonoJitInfo *ji;
2891
2892         g_assert (this);
2893         g_assert (addr);
2894
2895         class = this->vtable->klass;
2896
2897         if ((ji = mono_jit_info_table_find (domain, addr))) {
2898                 method = ji->method;
2899                 delegate->method_info = mono_method_get_object (domain, method, NULL);
2900         }
2901
2902         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
2903                 g_assert (method);
2904                 method = mono_marshal_get_remoting_invoke (method);
2905                 delegate->method_ptr = mono_compile_method (method);
2906                 delegate->target = target;
2907         } else {
2908                 delegate->method_ptr = addr;
2909                 delegate->target = target;
2910         }
2911 }
2912
2913 /**
2914  * mono_method_call_message_new:
2915  *
2916  * Translates arguments pointers into a Message.
2917  */
2918 MonoMethodMessage *
2919 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke, 
2920                               MonoDelegate **cb, MonoObject **state)
2921 {
2922         MonoDomain *domain = mono_domain_get ();
2923         MonoMethodSignature *sig = method->signature;
2924         MonoMethodMessage *msg;
2925         int i, count, type;
2926
2927         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class); 
2928         
2929         if (invoke) {
2930                 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
2931                 count =  sig->param_count - 2;
2932         } else {
2933                 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
2934                 count =  sig->param_count;
2935         }
2936
2937         for (i = 0; i < count; i++) {
2938                 gpointer vpos;
2939                 MonoClass *class;
2940                 MonoObject *arg;
2941
2942                 if (sig->params [i]->byref)
2943                         vpos = *((gpointer *)params [i]);
2944                 else 
2945                         vpos = params [i];
2946
2947                 type = sig->params [i]->type;
2948                 class = mono_class_from_mono_type (sig->params [i]);
2949
2950                 if (class->valuetype)
2951                         arg = mono_value_box (domain, class, vpos);
2952                 else 
2953                         arg = *((MonoObject **)vpos);
2954                       
2955                 mono_array_set (msg->args, gpointer, i, arg);
2956         }
2957
2958         if (cb != NULL && state != NULL) {
2959                 *cb = *((MonoDelegate **)params [i]);
2960                 i++;
2961                 *state = *((MonoObject **)params [i]);
2962         }
2963
2964         return msg;
2965 }
2966
2967 /**
2968  * mono_method_return_message_restore:
2969  *
2970  * Restore results from message based processing back to arguments pointers
2971  */
2972 void
2973 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
2974 {
2975         MonoMethodSignature *sig = method->signature;
2976         int i, j, type, size;
2977         for (i = 0, j = 0; i < sig->param_count; i++) {
2978                 MonoType *pt = sig->params [i];
2979
2980                 if (pt->byref) {
2981                         char *arg = mono_array_get (out_args, gpointer, j);
2982                         type = pt->type;
2983
2984                         switch (type) {
2985                         case MONO_TYPE_VOID:
2986                                 g_assert_not_reached ();
2987                                 break;
2988                         case MONO_TYPE_U1:
2989                         case MONO_TYPE_I1:
2990                         case MONO_TYPE_BOOLEAN:
2991                         case MONO_TYPE_U2:
2992                         case MONO_TYPE_I2:
2993                         case MONO_TYPE_CHAR:
2994                         case MONO_TYPE_U4:
2995                         case MONO_TYPE_I4:
2996                         case MONO_TYPE_I8:
2997                         case MONO_TYPE_U8:
2998                         case MONO_TYPE_R4:
2999                         case MONO_TYPE_R8:
3000                         case MONO_TYPE_VALUETYPE: {
3001                                 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
3002                                 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size); 
3003                                 break;
3004                         }
3005                         case MONO_TYPE_STRING:
3006                         case MONO_TYPE_CLASS: 
3007                         case MONO_TYPE_ARRAY:
3008                         case MONO_TYPE_SZARRAY:
3009                         case MONO_TYPE_OBJECT:
3010                                 **((MonoObject ***)params [i]) = (MonoObject *)arg;
3011                                 break;
3012                         default:
3013                                 g_assert_not_reached ();
3014                         }
3015
3016                         j++;
3017                 }
3018         }
3019 }
3020
3021 /**
3022  * mono_load_remote_field:
3023  * @this: pointer to an object
3024  * @klass: klass of the object containing @field
3025  * @field: the field to load
3026  * @res: a storage to store the result
3027  *
3028  * This method is called by the runtime on attempts to load fields of
3029  * transparent proxy objects. @this points to such TP, @klass is the class of
3030  * the object containing @field. @res is a storage location which can be
3031  * used to store the result.
3032  *
3033  * Returns: an address pointing to the value of field.
3034  */
3035 gpointer
3036 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
3037 {
3038         static MonoMethod *getter = NULL;
3039         MonoDomain *domain = mono_domain_get ();
3040         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3041         MonoClass *field_class;
3042         MonoMethodMessage *msg;
3043         MonoArray *out_args;
3044         MonoObject *exc;
3045         gpointer tmp;
3046
3047         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3048
3049         if (!res)
3050                 res = &tmp;
3051
3052         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3053                 mono_field_get_value (tp->rp->unwrapped_server, field, res);
3054                 return res;
3055         }
3056         
3057         if (!getter) {
3058                 int i;
3059
3060                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
3061                         MonoMethod *cm = mono_defaults.object_class->methods [i];
3062                
3063                         if (!strcmp (cm->name, "FieldGetter")) {
3064                                 getter = cm;
3065                                 break;
3066                         }
3067                 }
3068                 g_assert (getter);
3069         }
3070         
3071         field_class = mono_class_from_mono_type (field->type);
3072
3073         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3074         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
3075         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
3076
3077         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3078         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3079
3080         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3081
3082         if (exc) mono_raise_exception ((MonoException *)exc);
3083
3084         *res = mono_array_get (out_args, MonoObject *, 0);
3085
3086         if (field_class->valuetype) {
3087                 return ((char *)*res) + sizeof (MonoObject);
3088         } else
3089                 return res;
3090 }
3091
3092 MonoObject *
3093 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
3094 {
3095         static MonoMethod *getter = NULL;
3096         MonoDomain *domain = mono_domain_get ();
3097         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3098         MonoClass *field_class;
3099         MonoMethodMessage *msg;
3100         MonoArray *out_args;
3101         MonoObject *exc, *res;
3102
3103         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3104
3105         field_class = mono_class_from_mono_type (field->type);
3106
3107         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3108                 gpointer val;
3109                 if (field_class->valuetype) {
3110                         res = mono_object_new (domain, field_class);
3111                         val = ((gchar *) res) + sizeof (MonoObject);
3112                 } else {
3113                         val = &res;
3114                 }
3115                 mono_field_get_value (tp->rp->unwrapped_server, field, val);
3116                 return res;
3117         }
3118
3119         if (!getter) {
3120                 int i;
3121
3122                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
3123                         MonoMethod *cm = mono_defaults.object_class->methods [i];
3124                
3125                         if (!strcmp (cm->name, "FieldGetter")) {
3126                                 getter = cm;
3127                                 break;
3128                         }
3129                 }
3130                 g_assert (getter);
3131         }
3132         
3133         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3134         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
3135         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
3136
3137         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3138         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3139
3140         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3141
3142         if (exc) mono_raise_exception ((MonoException *)exc);
3143
3144         res = mono_array_get (out_args, MonoObject *, 0);
3145
3146         return res;
3147 }
3148
3149 /**
3150  * mono_store_remote_field:
3151  * @this: pointer to an object
3152  * @klass: klass of the object containing @field
3153  * @field: the field to load
3154  * @val: the value/object to store
3155  *
3156  * This method is called by the runtime on attempts to store fields of
3157  * transparent proxy objects. @this points to such TP, @klass is the class of
3158  * the object containing @field. @val is the new value to store in @field.
3159  */
3160 void
3161 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
3162 {
3163         static MonoMethod *setter = NULL;
3164         MonoDomain *domain = mono_domain_get ();
3165         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3166         MonoClass *field_class;
3167         MonoMethodMessage *msg;
3168         MonoArray *out_args;
3169         MonoObject *exc;
3170         MonoObject *arg;
3171
3172         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3173
3174         field_class = mono_class_from_mono_type (field->type);
3175
3176         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3177                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
3178                 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
3179                 return;
3180         }
3181
3182         if (!setter) {
3183                 int i;
3184
3185                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
3186                         MonoMethod *cm = mono_defaults.object_class->methods [i];
3187                
3188                         if (!strcmp (cm->name, "FieldSetter")) {
3189                                 setter = cm;
3190                                 break;
3191                         }
3192                 }
3193                 g_assert (setter);
3194         }
3195
3196         if (field_class->valuetype)
3197                 arg = mono_value_box (domain, field_class, val);
3198         else 
3199                 arg = *((MonoObject **)val);
3200                 
3201
3202         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3203         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
3204
3205         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3206         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3207         mono_array_set (msg->args, gpointer, 2, arg);
3208
3209         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3210
3211         if (exc) mono_raise_exception ((MonoException *)exc);
3212 }
3213
3214 void
3215 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
3216 {
3217         static MonoMethod *setter = NULL;
3218         MonoDomain *domain = mono_domain_get ();
3219         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3220         MonoClass *field_class;
3221         MonoMethodMessage *msg;
3222         MonoArray *out_args;
3223         MonoObject *exc;
3224
3225         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3226
3227         field_class = mono_class_from_mono_type (field->type);
3228
3229         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3230                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
3231                 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
3232                 return;
3233         }
3234
3235         if (!setter) {
3236                 int i;
3237
3238                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
3239                         MonoMethod *cm = mono_defaults.object_class->methods [i];
3240                
3241                         if (!strcmp (cm->name, "FieldSetter")) {
3242                                 setter = cm;
3243                                 break;
3244                         }
3245                 }
3246                 g_assert (setter);
3247         }
3248
3249         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3250         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
3251
3252         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3253         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3254         mono_array_set (msg->args, gpointer, 2, arg);
3255
3256         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3257
3258         if (exc) mono_raise_exception ((MonoException *)exc);
3259 }
3260