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