86b96b32a85430c60fe6ae0ca0fe331d471ab106
[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                 domain->entry_assembly = method->klass->image->assembly;
1440                 ves_icall_System_AppDomainSetup_InitAppDomainSetup (domain->setup);
1441         }
1442
1443         /* FIXME: check signature of method */
1444         if (method->signature->ret->type == MONO_TYPE_I4) {
1445                 MonoObject *res;
1446                 res = mono_runtime_invoke (method, NULL, pa, exc);
1447                 if (!exc || !*exc)
1448                         rval = *(guint32 *)((char *)res + sizeof (MonoObject));
1449                 else
1450                         rval = -1;
1451
1452                 mono_environment_exitcode_set (rval);
1453         } else {
1454                 mono_runtime_invoke (method, NULL, pa, exc);
1455                 if (!exc || !*exc)
1456                         rval = 0;
1457                 else {
1458                         /* If the return type of Main is void, only
1459                          * set the exitcode if an exception was thrown
1460                          * (we don't want to blow away an
1461                          * explicitly-set exit code)
1462                          */
1463                         rval = -1;
1464                         mono_environment_exitcode_set (rval);
1465                 }
1466         }
1467
1468         return rval;
1469 }
1470
1471 void
1472 mono_install_runtime_invoke (MonoInvokeFunc func)
1473 {
1474         default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
1475 }
1476
1477 MonoObject*
1478 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
1479                            MonoObject **exc)
1480 {
1481         MonoMethodSignature *sig = method->signature;
1482         gpointer *pa = NULL;
1483         int i;
1484                 
1485         if (NULL != params) {
1486                 pa = alloca (sizeof (gpointer) * mono_array_length (params));
1487                 for (i = 0; i < mono_array_length (params); i++) {
1488                         if (sig->params [i]->byref) {
1489                                 /* nothing to do */
1490                         }
1491
1492                         switch (sig->params [i]->type) {
1493                         case MONO_TYPE_U1:
1494                         case MONO_TYPE_I1:
1495                         case MONO_TYPE_BOOLEAN:
1496                         case MONO_TYPE_U2:
1497                         case MONO_TYPE_I2:
1498                         case MONO_TYPE_CHAR:
1499                         case MONO_TYPE_U:
1500                         case MONO_TYPE_I:
1501                         case MONO_TYPE_U4:
1502                         case MONO_TYPE_I4:
1503                         case MONO_TYPE_U8:
1504                         case MONO_TYPE_I8:
1505                         case MONO_TYPE_R4:
1506                         case MONO_TYPE_R8:
1507                         case MONO_TYPE_VALUETYPE:
1508                                 g_assert (((gpointer*)params->vector) [i]);
1509                                 pa [i] = (char *)(((gpointer *)params->vector)[i]) + sizeof (MonoObject);
1510                                 break;
1511                         case MONO_TYPE_STRING:
1512                         case MONO_TYPE_OBJECT:
1513                         case MONO_TYPE_CLASS:
1514                         case MONO_TYPE_ARRAY:
1515                         case MONO_TYPE_SZARRAY:
1516                                 if (sig->params [i]->byref)
1517                                         pa [i] = &(((gpointer *)params->vector)[i]);
1518                                 else
1519                                         pa [i] = (char *)(((gpointer *)params->vector)[i]);
1520                                 break;
1521                         default:
1522                                 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
1523                         }
1524                 }
1525         }
1526
1527         if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
1528                 if (!obj) {
1529                         obj = mono_object_new (mono_domain_get (), method->klass);
1530                         if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
1531                                 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
1532                         }
1533                 }
1534                 mono_runtime_invoke (method, obj, pa, exc);
1535                 return obj;
1536         } else
1537                 return mono_runtime_invoke (method, obj, pa, exc);
1538 }
1539
1540 static void
1541 out_of_memory (size_t size)
1542 {
1543         /* 
1544          * we could allocate at program startup some memory that we could release 
1545          * back to the system at this point if we're really low on memory (ie, size is
1546          * lower than the memory we set apart)
1547          */
1548         mono_raise_exception (mono_domain_get ()->out_of_memory_ex);
1549 }
1550
1551 /**
1552  * mono_object_allocate:
1553  * @size: number of bytes to allocate
1554  *
1555  * This is a very simplistic routine until we have our GC-aware
1556  * memory allocator. 
1557  *
1558  * Returns: an allocated object of size @size, or NULL on failure.
1559  */
1560 static inline void *
1561 mono_object_allocate (size_t size)
1562 {
1563 #if HAVE_BOEHM_GC
1564         /* if this is changed to GC_debug_malloc(), we need to change also metadata/gc.c */
1565         void *o = GC_MALLOC (size);
1566 #else
1567         void *o = calloc (1, size);
1568 #endif
1569         mono_stats.new_object_count++;
1570
1571         if (!o)
1572                 out_of_memory (size);
1573         return o;
1574 }
1575
1576 #if CREATION_SPEEDUP
1577 static inline void *
1578 mono_object_allocate_spec (size_t size, void *gcdescr)
1579 {
1580         /* if this is changed to GC_debug_malloc(), we need to change also metadata/gc.c */
1581         void *o = GC_GCJ_MALLOC (size, gcdescr);
1582         mono_stats.new_object_count++;
1583
1584         if (!o)
1585                 out_of_memory (size);
1586         return o;
1587 }
1588 #endif
1589
1590 /**
1591  * mono_object_free:
1592  *
1593  * Frees the memory used by the object.  Debugging purposes
1594  * only, as we will have our GC system.
1595  */
1596 void
1597 mono_object_free (MonoObject *o)
1598 {
1599 #if HAVE_BOEHM_GC
1600         g_error ("mono_object_free called with boehm gc.");
1601 #else
1602         MonoClass *c = o->vtable->klass;
1603         
1604         memset (o, 0, c->instance_size);
1605         free (o);
1606 #endif
1607 }
1608
1609 /**
1610  * mono_object_new:
1611  * @klass: the class of the object that we want to create
1612  *
1613  * Returns: A newly created object whose definition is
1614  * looked up using @klass
1615  */
1616 MonoObject *
1617 mono_object_new (MonoDomain *domain, MonoClass *klass)
1618 {
1619         MONO_ARCH_SAVE_REGS;
1620         return mono_object_new_specific (mono_class_vtable (domain, klass));
1621 }
1622
1623 /**
1624  * mono_object_new_specific:
1625  * @vtable: the vtable of the object that we want to create
1626  *
1627  * Returns: A newly created object with class and domain specified
1628  * by @vtable
1629  */
1630 MonoObject *
1631 mono_object_new_specific (MonoVTable *vtable)
1632 {
1633         MonoObject *o;
1634
1635         MONO_ARCH_SAVE_REGS;
1636         
1637         if (vtable->remote)
1638         {
1639                 gpointer pa [1];
1640                 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
1641
1642                 if (im == NULL) {
1643                         MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
1644                         int i;
1645
1646                         if (!klass->inited)
1647                                 mono_class_init (klass);
1648
1649                         for (i = 0; i < klass->method.count; ++i) {
1650                                 if (!strcmp ("CreateProxyForType", klass->methods [i]->name) &&
1651                                         klass->methods [i]->signature->param_count == 1) {
1652                                         im = klass->methods [i];
1653                                         break;
1654                                 }
1655                         }
1656                         g_assert (im);
1657                         vtable->domain->create_proxy_for_type_method = im;
1658                 }
1659         
1660                 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
1661
1662                 o = mono_runtime_invoke (im, NULL, pa, NULL);           
1663                 if (o != NULL) return o;
1664         }
1665
1666         return mono_object_new_alloc_specific (vtable);
1667 }
1668
1669 MonoObject *
1670 mono_object_new_fast (MonoVTable *vtable)
1671 {
1672         MonoObject *o;
1673         MONO_ARCH_SAVE_REGS;
1674
1675 #if CREATION_SPEEDUP
1676         if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
1677                 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
1678         } else {
1679 //              printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name);
1680                 o = mono_object_allocate (vtable->klass->instance_size);
1681                 o->vtable = vtable;
1682         }
1683 #else
1684         o = mono_object_allocate (vtable->klass->instance_size);
1685         o->vtable = vtable;
1686 #endif
1687         return o;
1688 }
1689
1690 MonoObject *
1691 mono_object_new_alloc_specific (MonoVTable *vtable)
1692 {
1693         MonoObject *o;
1694
1695 #if CREATION_SPEEDUP
1696         if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
1697                 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
1698         } else {
1699 //              printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name);
1700                 o = mono_object_allocate (vtable->klass->instance_size);
1701                 o->vtable = vtable;
1702         }
1703 #else
1704         o = mono_object_allocate (vtable->klass->instance_size);
1705         o->vtable = vtable;
1706 #endif
1707         if (vtable->klass->has_finalize)
1708                 mono_object_register_finalizer (o);
1709         
1710         mono_profiler_allocation (o, vtable->klass);
1711         return o;
1712 }
1713
1714 /**
1715  * mono_object_new_from_token:
1716  * @image: Context where the type_token is hosted
1717  * @token: a token of the type that we want to create
1718  *
1719  * Returns: A newly created object whose definition is
1720  * looked up using @token in the @image image
1721  */
1722 MonoObject *
1723 mono_object_new_from_token  (MonoDomain *domain, MonoImage *image, guint32 token)
1724 {
1725         MonoClass *class;
1726
1727         class = mono_class_get (image, token);
1728
1729         return mono_object_new (domain, class);
1730 }
1731
1732
1733 /**
1734  * mono_object_clone:
1735  * @obj: the object to clone
1736  *
1737  * Returns: A newly created object who is a shallow copy of @obj
1738  */
1739 MonoObject *
1740 mono_object_clone (MonoObject *obj)
1741 {
1742         MonoObject *o;
1743         int size;
1744
1745         size = obj->vtable->klass->instance_size;
1746         o = mono_object_allocate (size);
1747         mono_profiler_allocation (o, obj->vtable->klass);
1748
1749         memcpy (o, obj, size);
1750
1751         if (obj->vtable->klass->has_finalize)
1752                 mono_object_register_finalizer (o);
1753         return o;
1754 }
1755
1756 /**
1757  * mono_array_clone:
1758  * @array: the array to clone
1759  *
1760  * Returns: A newly created array who is a shallow copy of @array
1761  */
1762 MonoArray*
1763 mono_array_clone (MonoArray *array)
1764 {
1765         MonoArray *o;
1766         int size, i;
1767         guint32 *sizes;
1768         MonoClass *klass = array->obj.vtable->klass;
1769
1770         MONO_ARCH_SAVE_REGS;
1771
1772         if (array->bounds == NULL) {
1773                 size = mono_array_length (array);
1774                 o = mono_array_new_full (((MonoObject *)array)->vtable->domain,
1775                                          klass, &size, NULL);
1776
1777                 size *= mono_array_element_size (klass);
1778                 memcpy (o, array, sizeof (MonoArray) + size);
1779
1780                 return o;
1781         }
1782         
1783         sizes = alloca (klass->rank * sizeof(guint32) * 2);
1784         size = mono_array_element_size (klass);
1785         for (i = 0; i < klass->rank; ++i) {
1786                 sizes [i] = array->bounds [i].length;
1787                 size *= array->bounds [i].length;
1788                 sizes [i + klass->rank] = array->bounds [i].lower_bound;
1789         }
1790         o = mono_array_new_full (((MonoObject *)array)->vtable->domain, 
1791                                  klass, sizes, sizes + klass->rank);
1792         memcpy (o, array, sizeof(MonoArray) + size);
1793
1794         return o;
1795 }
1796
1797 /* helper macros to check for overflow when calculating the size of arrays */
1798 #define MYGUINT32_MAX 4294967295U
1799 #define CHECK_ADD_OVERFLOW_UN(a,b) \
1800         (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
1801 #define CHECK_MUL_OVERFLOW_UN(a,b) \
1802         ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
1803         (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
1804
1805 /*
1806  * mono_array_new_full:
1807  * @domain: domain where the object is created
1808  * @array_class: array class
1809  * @lengths: lengths for each dimension in the array
1810  * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
1811  *
1812  * This routine creates a new array objects with the given dimensions,
1813  * lower bounds and type.
1814  */
1815 MonoArray*
1816 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, 
1817                      guint32 *lengths, guint32 *lower_bounds)
1818 {
1819         guint32 byte_len, len;
1820         MonoObject *o;
1821         MonoArray *array;
1822         MonoArrayBounds *bounds;
1823         MonoVTable *vtable;
1824         int i;
1825
1826         if (!array_class->inited)
1827                 mono_class_init (array_class);
1828
1829         byte_len = mono_array_element_size (array_class);
1830         len = 1;
1831
1832         if (array_class->rank == 1 &&
1833             (lower_bounds == NULL || lower_bounds [0] == 0)) {
1834                 bounds = NULL;
1835                 len = lengths [0];
1836         } else {
1837         #if HAVE_BOEHM_GC
1838                 bounds = GC_MALLOC (sizeof (MonoArrayBounds) * array_class->rank);
1839         #else
1840                 bounds = g_malloc0 (sizeof (MonoArrayBounds) * array_class->rank);
1841         #endif
1842                 for (i = 0; i < array_class->rank; ++i) {
1843                         bounds [i].length = lengths [i];
1844                         if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
1845                                 out_of_memory (MYGUINT32_MAX);
1846                         len *= lengths [i];
1847                 }
1848
1849                 if (lower_bounds)
1850                         for (i = 0; i < array_class->rank; ++i)
1851                                 bounds [i].lower_bound = lower_bounds [i];
1852         }
1853
1854         if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
1855                 out_of_memory (MYGUINT32_MAX);
1856         byte_len *= len;
1857         if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
1858                 out_of_memory (MYGUINT32_MAX);
1859         byte_len += sizeof (MonoArray);
1860         /* 
1861          * Following three lines almost taken from mono_object_new ():
1862          * they need to be kept in sync.
1863          */
1864         vtable = mono_class_vtable (domain, array_class);
1865 #if CREATION_SPEEDUP
1866         if (vtable->gc_descr != GC_NO_DESCRIPTOR)
1867                 o = mono_object_allocate_spec (byte_len, vtable);
1868         else {
1869                 o = mono_object_allocate (byte_len);
1870                 o->vtable = vtable;
1871         }
1872 #else
1873         o = mono_object_allocate (byte_len);
1874         o->vtable = vtable;
1875 #endif
1876
1877         array = (MonoArray*)o;
1878
1879         array->bounds = bounds;
1880         array->max_length = len;
1881
1882         mono_profiler_allocation (o, array_class);
1883
1884         return array;
1885 }
1886
1887 /*
1888  * mono_array_new:
1889  * @domain: domain where the object is created
1890  * @eclass: element class
1891  * @n: number of array elements
1892  *
1893  * This routine creates a new szarray with @n elements of type @eclass.
1894  */
1895 MonoArray *
1896 mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
1897 {
1898         MonoClass *ac;
1899
1900         MONO_ARCH_SAVE_REGS;
1901
1902         ac = mono_array_class_get (eclass, 1);
1903         g_assert (ac != NULL);
1904
1905         return mono_array_new_specific (mono_class_vtable (domain, ac), n);
1906 }
1907
1908 /*
1909  * mono_array_new_specific:
1910  * @vtable: a vtable in the appropriate domain for an initialized class
1911  * @n: number of array elements
1912  *
1913  * This routine is a fast alternative to mono_array_new() for code which
1914  * can be sure about the domain it operates in.
1915  */
1916 MonoArray *
1917 mono_array_new_specific (MonoVTable *vtable, guint32 n)
1918 {
1919         MonoObject *o;
1920         MonoArray *ao;
1921         guint32 byte_len, elem_size;
1922
1923         MONO_ARCH_SAVE_REGS;
1924
1925         elem_size = mono_array_element_size (vtable->klass);
1926         if (CHECK_MUL_OVERFLOW_UN (n, elem_size))
1927                 out_of_memory (MYGUINT32_MAX);
1928         byte_len = n * elem_size;
1929         if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
1930                 out_of_memory (MYGUINT32_MAX);
1931         byte_len += sizeof (MonoArray);
1932 #if CREATION_SPEEDUP
1933         if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
1934                 o = mono_object_allocate_spec (byte_len, vtable);
1935         } else {
1936 //              printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name);
1937                 o = mono_object_allocate (byte_len);
1938                 o->vtable = vtable;
1939         }
1940 #else
1941         o = mono_object_allocate (byte_len);
1942         o->vtable = vtable;
1943 #endif
1944
1945         ao = (MonoArray *)o;
1946         ao->bounds = NULL;
1947         ao->max_length = n;
1948         mono_profiler_allocation (o, vtable->klass);
1949
1950         return ao;
1951 }
1952
1953 /**
1954  * mono_string_new_utf16:
1955  * @text: a pointer to an utf16 string
1956  * @len: the length of the string
1957  *
1958  * Returns: A newly created string object which contains @text.
1959  */
1960 MonoString *
1961 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
1962 {
1963         MonoString *s;
1964         
1965         s = mono_string_new_size (domain, len);
1966         g_assert (s != NULL);
1967
1968         memcpy (mono_string_chars (s), text, len * 2);
1969
1970         return s;
1971 }
1972
1973 /**
1974  * mono_string_new_size:
1975  * @text: a pointer to an utf16 string
1976  * @len: the length of the string
1977  *
1978  * Returns: A newly created string object of @len
1979  */
1980 MonoString *
1981 mono_string_new_size (MonoDomain *domain, gint32 len)
1982 {
1983         MonoString *s;
1984         MonoVTable *vtable;
1985
1986         vtable = mono_class_vtable (domain, mono_defaults.string_class);
1987
1988 #if CREATION_SPEEDUP
1989         if (vtable->gc_descr != GC_NO_DESCRIPTOR)
1990                 s = mono_object_allocate_spec (sizeof (MonoString) + ((len + 1) * 2), vtable);
1991         else {
1992                 s = (MonoString*)mono_object_allocate (sizeof (MonoString) + ((len + 1) * 2));
1993                 s->object.vtable = vtable;
1994         }
1995 #else
1996         s = (MonoString*)mono_object_allocate (sizeof (MonoString) + ((len + 1) * 2));
1997         s->object.vtable = vtable;
1998 #endif
1999
2000         s->length = len;
2001         mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
2002
2003         return s;
2004 }
2005
2006 /*
2007  * mono_string_new_len:
2008  * @text: a pointer to an utf8 string
2009  * @length: number of bytes in @text to consider
2010  *
2011  * Returns: A newly created string object which contains @text.
2012  */
2013 MonoString*
2014 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
2015 {
2016         GError *error = NULL;
2017         MonoString *o = NULL;
2018         guint16 *ut;
2019         glong items_written;
2020
2021         ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
2022
2023         if (!error)
2024                 o = mono_string_new_utf16 (domain, ut, items_written);
2025         else 
2026                 g_error_free (error);
2027
2028         g_free (ut);
2029
2030         return o;
2031 }
2032
2033 /**
2034  * mono_string_new:
2035  * @text: a pointer to an utf8 string
2036  *
2037  * Returns: A newly created string object which contains @text.
2038  */
2039 MonoString*
2040 mono_string_new (MonoDomain *domain, const char *text)
2041 {
2042         GError *error = NULL;
2043         MonoString *o = NULL;
2044         guint16 *ut;
2045         glong items_written;
2046         int l;
2047
2048         l = strlen (text);
2049         
2050         ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
2051
2052         if (!error)
2053                 o = mono_string_new_utf16 (domain, ut, items_written);
2054         else 
2055                 g_error_free (error);
2056
2057         g_free (ut);
2058
2059         return o;
2060 }
2061
2062 /*
2063  * mono_string_new_wrapper:
2064  * @text: pointer to utf8 characters.
2065  *
2066  * Helper function to create a string object from @text in the current domain.
2067  */
2068 MonoString*
2069 mono_string_new_wrapper (const char *text)
2070 {
2071         MonoDomain *domain = mono_domain_get ();
2072
2073         MONO_ARCH_SAVE_REGS;
2074
2075         if (text)
2076                 return mono_string_new (domain, text);
2077
2078         return NULL;
2079 }
2080
2081 /**
2082  * mono_value_box:
2083  * @class: the class of the value
2084  * @value: a pointer to the unboxed data
2085  *
2086  * Returns: A newly created object which contains @value.
2087  */
2088 MonoObject *
2089 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
2090 {
2091         MonoObject *res;
2092         int size;
2093         MonoVTable *vtable;
2094
2095         g_assert (class->valuetype);
2096
2097         vtable = mono_class_vtable (domain, class);
2098         size = mono_class_instance_size (class);
2099         res = mono_object_allocate (size);
2100         res->vtable = vtable;
2101         mono_profiler_allocation (res, class);
2102
2103         size = size - sizeof (MonoObject);
2104
2105 #if NO_UNALIGNED_ACCESS
2106         memcpy ((char *)res + sizeof (MonoObject), value, size);
2107 #else
2108         switch (size) {
2109         case 1:
2110                 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
2111                 break;
2112         case 2:
2113                 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
2114                 break;
2115         case 4:
2116                 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
2117                 break;
2118         case 8:
2119                 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
2120                 break;
2121         default:
2122                 memcpy ((char *)res + sizeof (MonoObject), value, size);
2123         }
2124 #endif
2125         if (class->has_finalize)
2126                 mono_object_register_finalizer (res);
2127         return res;
2128 }
2129
2130 gpointer
2131 mono_object_unbox (MonoObject *obj)
2132 {
2133         /* add assert for valuetypes? */
2134         return ((char*)obj) + sizeof (MonoObject);
2135 }
2136
2137 /**
2138  * mono_object_isinst:
2139  * @obj: an object
2140  * @klass: a pointer to a class 
2141  *
2142  * Returns: @obj if @obj is derived from @klass
2143  */
2144 MonoObject *
2145 mono_object_isinst (MonoObject *obj, MonoClass *klass)
2146 {
2147         if (!klass->inited)
2148                 mono_class_init (klass);
2149
2150         if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) 
2151                 return mono_object_isinst_mbyref (obj, klass);
2152
2153         if (!obj)
2154                 return NULL;
2155
2156         return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
2157 }
2158
2159 MonoObject *
2160 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
2161 {
2162         MonoVTable *vt;
2163
2164         if (!obj)
2165                 return NULL;
2166
2167         vt = obj->vtable;
2168         
2169         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2170                 if ((klass->interface_id <= vt->max_interface_id) &&
2171                     (vt->interface_offsets [klass->interface_id] != 0))
2172                         return obj;
2173         }
2174         else {
2175                 MonoClass *oklass = vt->klass;
2176                 if ((oklass == mono_defaults.transparent_proxy_class))
2177                         oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2178         
2179                 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
2180                         return obj;
2181         }
2182
2183         if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info) 
2184         {
2185                 MonoDomain *domain = mono_domain_get ();
2186                 MonoObject *res;
2187                 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
2188                 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
2189                 MonoMethod *im = NULL;
2190                 gpointer pa [2];
2191                 int i;
2192         
2193                 for (i = 0; i < rpklass->method.count; ++i) {
2194                         if (!strcmp ("CanCastTo", rpklass->methods [i]->name)) {
2195                                 im = rpklass->methods [i];
2196                                 break;
2197                         }
2198                 }
2199         
2200                 im = mono_object_get_virtual_method (rp, im);
2201                 g_assert (im);
2202         
2203                 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
2204                 pa [1] = obj;
2205
2206                 res = mono_runtime_invoke (im, rp, pa, NULL);
2207         
2208                 if (*(MonoBoolean *) mono_object_unbox(res)) {
2209                         /* Update the vtable of the remote type, so it can safely cast to this new type */
2210                         mono_upgrade_remote_class (domain, ((MonoTransparentProxy *)obj)->remote_class, klass);
2211                         obj->vtable = ((MonoTransparentProxy *)obj)->remote_class->vtable;
2212                         return obj;
2213                 }
2214         }
2215
2216         return NULL;
2217 }
2218
2219 /**
2220  * mono_object_castclass_mbyref:
2221  * @obj: an object
2222  * @klass: a pointer to a class 
2223  *
2224  * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
2225  */
2226 MonoObject *
2227 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
2228 {
2229         if (!obj) return NULL;
2230         if (mono_object_isinst_mbyref (obj, klass)) return obj;
2231                 
2232         mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
2233                                                         "System",
2234                                                         "InvalidCastException"));
2235         return NULL;
2236 }
2237
2238 typedef struct {
2239         MonoDomain *orig_domain;
2240         char *ins;
2241         MonoString *res;
2242 } LDStrInfo;
2243
2244 static void
2245 str_lookup (MonoDomain *domain, gpointer user_data)
2246 {
2247         LDStrInfo *info = user_data;
2248         if (info->res || domain == info->orig_domain)
2249                 return;
2250         mono_domain_lock (domain);
2251         info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
2252         mono_domain_unlock (domain);
2253 }
2254
2255 static MonoString*
2256 mono_string_is_interned_lookup (MonoString *str, int insert)
2257 {
2258         MonoGHashTable *ldstr_table;
2259         MonoString *res;
2260         MonoDomain *domain;
2261         char *ins = g_malloc (4 + str->length * 2);
2262         char *p;
2263         
2264         /* Encode the length */
2265         /* Same code as in mono_image_insert_string () */
2266         p = ins;
2267         mono_metadata_encode_value (1 | (2 * str->length), p, &p);
2268
2269         /*
2270          * ins is stored in the hash table as a key and needs to have the same
2271          * representation as in the metadata: we swap the character bytes on big
2272          * endian boxes.
2273          */
2274 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
2275         {
2276                 int i;
2277                 char *p2 = (char *)mono_string_chars (str);
2278                 for (i = 0; i < str->length; ++i) {
2279                         *p++ = p2 [1];
2280                         *p++ = p2 [0];
2281                         p2 += 2;
2282                 }
2283         }
2284 #else
2285         memcpy (p, mono_string_chars (str), str->length * 2);
2286 #endif
2287         domain = ((MonoObject *)str)->vtable->domain;
2288         ldstr_table = domain->ldstr_table;
2289         mono_domain_lock (domain);
2290         if ((res = mono_g_hash_table_lookup (ldstr_table, ins))) {
2291                 mono_domain_unlock (domain);
2292                 g_free (ins);
2293                 return res;
2294         }
2295         if (insert) {
2296                 mono_g_hash_table_insert (ldstr_table, ins, str);
2297                 mono_domain_unlock (domain);
2298                 return str;
2299         } else {
2300                 LDStrInfo ldstr_info;
2301                 ldstr_info.orig_domain = domain;
2302                 ldstr_info.ins = ins;
2303                 ldstr_info.res = NULL;
2304
2305                 mono_domain_foreach (str_lookup, &ldstr_info);
2306                 if (ldstr_info.res) {
2307                         /* 
2308                          * the string was already interned in some other domain:
2309                          * intern it in the current one as well.
2310                          */
2311                         mono_g_hash_table_insert (ldstr_table, ins, str);
2312                         mono_domain_unlock (domain);
2313                         return str;
2314                 }
2315         }
2316         mono_domain_unlock (domain);
2317         g_free (ins);
2318         return NULL;
2319 }
2320
2321 MonoString*
2322 mono_string_is_interned (MonoString *o)
2323 {
2324         return mono_string_is_interned_lookup (o, FALSE);
2325 }
2326
2327 MonoString*
2328 mono_string_intern (MonoString *str)
2329 {
2330         return mono_string_is_interned_lookup (str, TRUE);
2331 }
2332
2333 /*
2334  * mono_ldstr:
2335  * @domain: the domain where the string will be used.
2336  * @image: a metadata context
2337  * @idx: index into the user string table.
2338  * 
2339  * Implementation for the ldstr opcode.
2340  */
2341 MonoString*
2342 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
2343 {
2344         const char *str, *sig;
2345         MonoString *o;
2346         size_t len2;
2347
2348         MONO_ARCH_SAVE_REGS;
2349
2350         if (image->dynamic)
2351                 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx);
2352         else
2353                 sig = str = mono_metadata_user_string (image, idx);
2354
2355         mono_domain_lock (domain);
2356         if ((o = mono_g_hash_table_lookup (domain->ldstr_table, sig))) {
2357                 mono_domain_unlock (domain);
2358                 return o;
2359         }
2360         
2361         len2 = mono_metadata_decode_blob_size (str, &str);
2362         len2 >>= 1;
2363
2364         o = mono_string_new_utf16 (domain, (guint16*)str, len2);
2365 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
2366         {
2367                 int i;
2368                 guint16 *p2 = (guint16*)mono_string_chars (o);
2369                 for (i = 0; i < len2; ++i) {
2370                         *p2 = GUINT16_FROM_LE (*p2);
2371                         ++p2;
2372                 }
2373         }
2374 #endif
2375         mono_g_hash_table_insert (domain->ldstr_table, (gpointer)sig, o);
2376         mono_domain_unlock (domain);
2377
2378         return o;
2379 }
2380
2381 /*
2382  * mono_string_to_utf8:
2383  * @s: a System.String
2384  *
2385  * Return the UTF8 representation for @s.
2386  * the resulting buffer nedds to be freed with g_free().
2387  */
2388 char *
2389 mono_string_to_utf8 (MonoString *s)
2390 {
2391         char *as;
2392         GError *error = NULL;
2393
2394         if (s == NULL)
2395                 return NULL;
2396
2397         if (!s->length)
2398                 return g_strdup ("");
2399
2400         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, NULL, &error);
2401         if (error) {
2402                 g_warning (error->message);
2403                 g_error_free (error);
2404         }
2405
2406         return as;
2407 }
2408
2409 /*
2410  * mono_string_to_utf16:
2411  * @s: a MonoString
2412  *
2413  * Return an null-terminated array of the utf-16 chars
2414  * contained in @s. The result must be freed with g_free().
2415  * This is a temporary helper until our string implementation
2416  * is reworked to always include the null terminating char.
2417  */
2418 gunichar2 *
2419 mono_string_to_utf16 (MonoString *s)
2420 {
2421         char *as;
2422
2423         if (s == NULL)
2424                 return NULL;
2425
2426         as = g_malloc ((s->length * 2) + 2);
2427         as [(s->length * 2)] = '\0';
2428         as [(s->length * 2) + 1] = '\0';
2429
2430         if (!s->length) {
2431                 return (gunichar2 *)(as);
2432         }
2433         
2434         memcpy (as, mono_string_chars(s), s->length * 2);
2435         return (gunichar2 *)(as);
2436 }
2437
2438 /*
2439  * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString
2440  */
2441 MonoString *
2442 mono_string_from_utf16 (gunichar2 *data)
2443 {
2444         MonoDomain *domain = mono_domain_get ();
2445         int len = 0;
2446
2447         if (!data)
2448                 return NULL;
2449
2450         while (data [len]) len++;
2451
2452         return mono_string_new_utf16 (domain, data, len);
2453 }
2454
2455 static void
2456 default_ex_handler (MonoException *ex)
2457 {
2458         MonoObject *o = (MonoObject*)ex;
2459         g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
2460         exit (1);
2461 }
2462
2463 static MonoExceptionFunc ex_handler = default_ex_handler;
2464
2465 void
2466 mono_install_handler        (MonoExceptionFunc func)
2467 {
2468         ex_handler = func? func: default_ex_handler;
2469 }
2470
2471 /*
2472  * mono_raise_exception:
2473  * @ex: exception object
2474  *
2475  * Signal the runtime that the exception @ex has been raised in unmanaged code.
2476  */
2477 void
2478 mono_raise_exception (MonoException *ex) 
2479 {
2480         /*
2481          * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
2482          * that will cause gcc to omit the function epilog, causing problems when
2483          * the JIT tries to walk the stack, since the return address on the stack
2484          * will point into the next function in the executable, not this one.
2485          */
2486
2487         ex_handler (ex);
2488 }
2489
2490 MonoWaitHandle *
2491 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
2492 {
2493         MonoWaitHandle *res;
2494
2495         res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
2496
2497         res->handle = handle;
2498
2499         return res;
2500 }
2501
2502 MonoAsyncResult *
2503 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data)
2504 {
2505         MonoAsyncResult *res;
2506
2507         res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
2508
2509         res->data = data;
2510         res->async_state = state;
2511         if (handle != NULL)
2512                 res->handle = (MonoObject *) mono_wait_handle_new (domain, handle);
2513
2514         res->sync_completed = FALSE;
2515         res->completed = FALSE;
2516
2517         return res;
2518 }
2519
2520 void
2521 mono_message_init (MonoDomain *domain,
2522                    MonoMethodMessage *this, 
2523                    MonoReflectionMethod *method,
2524                    MonoArray *out_args)
2525 {
2526         MonoMethodSignature *sig = method->method->signature;
2527         MonoString *name;
2528         int i, j;
2529         char **names;
2530         guint8 arg_type;
2531
2532         this->method = method;
2533
2534         this->args = mono_array_new (domain, mono_defaults.object_class, sig->param_count);
2535         this->arg_types = mono_array_new (domain, mono_defaults.byte_class, sig->param_count);
2536         this->async_result = NULL;
2537         this->call_type = CallType_Sync;
2538
2539         names = g_new (char *, sig->param_count);
2540         mono_method_get_param_names (method->method, (const char **) names);
2541         this->names = mono_array_new (domain, mono_defaults.string_class, sig->param_count);
2542         
2543         for (i = 0; i < sig->param_count; i++) {
2544                  name = mono_string_new (domain, names [i]);
2545                  mono_array_set (this->names, gpointer, i, name);       
2546         }
2547
2548         g_free (names);
2549         for (i = 0, j = 0; i < sig->param_count; i++) {
2550
2551                 if (sig->params [i]->byref) {
2552                         if (out_args) {
2553                                 gpointer arg = mono_array_get (out_args, gpointer, j);
2554                                 mono_array_set (this->args, gpointer, i, arg);
2555                                 j++;
2556                         }
2557                         arg_type = 2;
2558                         if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
2559                                 arg_type |= 1;
2560                 } else {
2561                         arg_type = 1;
2562                 }
2563                 mono_array_set (this->arg_types, guint8, i, arg_type);
2564         }
2565 }
2566
2567 /**
2568  * mono_remoting_invoke:
2569  * @real_proxy: pointer to a RealProxy object
2570  * @msg: The MonoMethodMessage to execute
2571  * @exc: used to store exceptions
2572  * @out_args: used to store output arguments
2573  *
2574  * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
2575  * IMessage interface and it is not trivial to extract results from there. So
2576  * we call an helper method PrivateInvoke instead of calling
2577  * RealProxy::Invoke() directly.
2578  *
2579  * Returns: the result object.
2580  */
2581 MonoObject *
2582 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, 
2583                       MonoObject **exc, MonoArray **out_args)
2584 {
2585         MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
2586         gpointer pa [4];
2587
2588         /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
2589
2590         if (!im) {
2591                 MonoClass *klass;
2592                 int i;
2593
2594                 klass = mono_defaults.real_proxy_class; 
2595                        
2596                 for (i = 0; i < klass->method.count; ++i) {
2597                         if (!strcmp ("PrivateInvoke", klass->methods [i]->name) &&
2598                             klass->methods [i]->signature->param_count == 4) {
2599                                 im = klass->methods [i];
2600                                 break;
2601                         }
2602                 }
2603         
2604                 g_assert (im);
2605                 real_proxy->vtable->domain->private_invoke_method = im;
2606         }
2607
2608         pa [0] = real_proxy;
2609         pa [1] = msg;
2610         pa [2] = exc;
2611         pa [3] = out_args;
2612
2613         return mono_runtime_invoke (im, NULL, pa, exc);
2614 }
2615
2616 MonoObject *
2617 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
2618                      MonoObject **exc, MonoArray **out_args) 
2619 {
2620         MonoDomain *domain; 
2621         MonoMethod *method;
2622         MonoMethodSignature *sig;
2623         int i, j, outarg_count = 0;
2624
2625         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
2626
2627                 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
2628                 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
2629                         target = tp->rp->unwrapped_server;
2630                 } else {
2631                         return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
2632                 }
2633         }
2634
2635         domain = mono_domain_get (); 
2636         method = msg->method->method;
2637         sig = method->signature;
2638
2639         for (i = 0; i < sig->param_count; i++) {
2640                 if (sig->params [i]->byref) 
2641                         outarg_count++;
2642         }
2643
2644         *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
2645         *exc = NULL;
2646
2647         for (i = 0, j = 0; i < sig->param_count; i++) {
2648                 if (sig->params [i]->byref) {
2649                         gpointer arg;
2650                         arg = mono_array_get (msg->args, gpointer, i);
2651                         mono_array_set (*out_args, gpointer, j, arg);
2652                         j++;
2653                 }
2654         }
2655
2656         return mono_runtime_invoke_array (method, target, msg->args, exc);
2657 }
2658
2659 void
2660 mono_print_unhandled_exception (MonoObject *exc)
2661 {
2662         char *message = (char *) "";
2663         MonoString *str; 
2664         MonoMethod *method;
2665         MonoClass *klass;
2666         gboolean free_message = FALSE;
2667         gint i;
2668
2669         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
2670                 klass = exc->vtable->klass;
2671                 method = NULL;
2672                 while (klass && method == NULL) {
2673                         for (i = 0; i < klass->method.count; ++i) {
2674                                 method = klass->methods [i];
2675                                 if (!strcmp ("ToString", method->name) &&
2676                                     method->signature->param_count == 0 &&
2677                                     method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
2678                                     method->flags & METHOD_ATTRIBUTE_PUBLIC) {
2679                                         break;
2680                                 }
2681                                 method = NULL;
2682                         }
2683                         
2684                         if (method == NULL)
2685                                 klass = klass->parent;
2686                 }
2687
2688                 g_assert (method);
2689
2690                 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
2691                 if (str) {
2692                         message = mono_string_to_utf8 (str);
2693                         free_message = TRUE;
2694                 }
2695         }                               
2696
2697         /*
2698          * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space, 
2699          *         exc->vtable->klass->name, message);
2700          */
2701         g_printerr ("\nUnhandled Exception: %s\n", message);
2702         
2703         if (free_message)
2704                 g_free (message);
2705 }
2706
2707 /**
2708  * mono_delegate_ctor:
2709  * @this: pointer to an uninitialized delegate object
2710  * @target: target object
2711  * @addr: pointer to native code
2712  *
2713  * This is used to initialize a delegate. We also insert the method_info if
2714  * we find the info with mono_jit_info_table_find().
2715  */
2716 void
2717 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
2718 {
2719         MonoDomain *domain = mono_domain_get ();
2720         MonoDelegate *delegate = (MonoDelegate *)this;
2721         MonoMethod *method = NULL;
2722         MonoClass *class;
2723         MonoJitInfo *ji;
2724
2725         g_assert (this);
2726         g_assert (addr);
2727
2728         class = this->vtable->klass;
2729
2730         if ((ji = mono_jit_info_table_find (domain, addr))) {
2731                 method = ji->method;
2732                 delegate->method_info = mono_method_get_object (domain, method, NULL);
2733         }
2734
2735         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
2736                 g_assert (method);
2737                 method = mono_marshal_get_remoting_invoke (method);
2738                 delegate->method_ptr = mono_compile_method (method);
2739                 delegate->target = target;
2740         } else {
2741                 delegate->method_ptr = addr;
2742                 delegate->target = target;
2743         }
2744 }
2745
2746 /**
2747  * mono_method_call_message_new:
2748  *
2749  * Translates arguments pointers into a Message.
2750  */
2751 MonoMethodMessage *
2752 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke, 
2753                               MonoDelegate **cb, MonoObject **state)
2754 {
2755         MonoDomain *domain = mono_domain_get ();
2756         MonoMethodSignature *sig = method->signature;
2757         MonoMethodMessage *msg;
2758         int i, count, type;
2759
2760         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class); 
2761         
2762         if (invoke) {
2763                 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
2764                 count =  sig->param_count - 2;
2765         } else {
2766                 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
2767                 count =  sig->param_count;
2768         }
2769
2770         for (i = 0; i < count; i++) {
2771                 gpointer vpos;
2772                 MonoClass *class;
2773                 MonoObject *arg;
2774
2775                 if (sig->params [i]->byref)
2776                         vpos = *((gpointer *)params [i]);
2777                 else 
2778                         vpos = params [i];
2779
2780                 type = sig->params [i]->type;
2781                 class = mono_class_from_mono_type (sig->params [i]);
2782
2783                 if (class->valuetype)
2784                         arg = mono_value_box (domain, class, vpos);
2785                 else 
2786                         arg = *((MonoObject **)vpos);
2787                       
2788                 mono_array_set (msg->args, gpointer, i, arg);
2789         }
2790
2791         if (cb != NULL && state != NULL) {
2792                 *cb = *((MonoDelegate **)params [i]);
2793                 i++;
2794                 *state = *((MonoObject **)params [i]);
2795         }
2796
2797         return msg;
2798 }
2799
2800 /**
2801  * mono_method_return_message_restore:
2802  *
2803  * Restore results from message based processing back to arguments pointers
2804  */
2805 void
2806 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
2807 {
2808         MonoMethodSignature *sig = method->signature;
2809         int i, j, type, size;
2810         for (i = 0, j = 0; i < sig->param_count; i++) {
2811                 MonoType *pt = sig->params [i];
2812
2813                 if (pt->byref) {
2814                         char *arg = mono_array_get (out_args, gpointer, j);
2815                         type = pt->type;
2816
2817                         switch (type) {
2818                         case MONO_TYPE_VOID:
2819                                 g_assert_not_reached ();
2820                                 break;
2821                         case MONO_TYPE_U1:
2822                         case MONO_TYPE_I1:
2823                         case MONO_TYPE_BOOLEAN:
2824                         case MONO_TYPE_U2:
2825                         case MONO_TYPE_I2:
2826                         case MONO_TYPE_CHAR:
2827                         case MONO_TYPE_U4:
2828                         case MONO_TYPE_I4:
2829                         case MONO_TYPE_I8:
2830                         case MONO_TYPE_U8:
2831                         case MONO_TYPE_R4:
2832                         case MONO_TYPE_R8:
2833                         case MONO_TYPE_VALUETYPE: {
2834                                 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
2835                                 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size); 
2836                                 break;
2837                         }
2838                         case MONO_TYPE_STRING:
2839                         case MONO_TYPE_CLASS: 
2840                         case MONO_TYPE_ARRAY:
2841                         case MONO_TYPE_SZARRAY:
2842                                 **((MonoObject ***)params [i]) = (MonoObject *)arg;
2843                                 break;
2844                         default:
2845                                 g_assert_not_reached ();
2846                         }
2847
2848                         j++;
2849                 }
2850         }
2851 }
2852
2853 /**
2854  * mono_load_remote_field:
2855  * @this: pointer to an object
2856  * @klass: klass of the object containing @field
2857  * @field: the field to load
2858  * @res: a storage to store the result
2859  *
2860  * This method is called by the runtime on attempts to load fields of
2861  * transparent proxy objects. @this points to such TP, @klass is the class of
2862  * the object containing @field. @res is a storage location which can be
2863  * used to store the result.
2864  *
2865  * Returns: an address pointing to the value of field.
2866  */
2867 gpointer
2868 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
2869 {
2870         static MonoMethod *getter = NULL;
2871         MonoDomain *domain = mono_domain_get ();
2872         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
2873         MonoClass *field_class;
2874         MonoMethodMessage *msg;
2875         MonoArray *out_args;
2876         MonoObject *exc;
2877         gpointer tmp;
2878
2879         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
2880
2881         if (!res)
2882                 res = &tmp;
2883
2884         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
2885                 mono_field_get_value (tp->rp->unwrapped_server, field, res);
2886                 return res;
2887         }
2888         
2889         if (!getter) {
2890                 int i;
2891
2892                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
2893                         MonoMethod *cm = mono_defaults.object_class->methods [i];
2894                
2895                         if (!strcmp (cm->name, "FieldGetter")) {
2896                                 getter = cm;
2897                                 break;
2898                         }
2899                 }
2900                 g_assert (getter);
2901         }
2902         
2903         field_class = mono_class_from_mono_type (field->type);
2904
2905         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
2906         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
2907         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
2908
2909         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
2910         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
2911
2912         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
2913
2914         if (exc) mono_raise_exception ((MonoException *)exc);
2915
2916         *res = mono_array_get (out_args, MonoObject *, 0);
2917
2918         if (field_class->valuetype) {
2919                 return ((char *)*res) + sizeof (MonoObject);
2920         } else
2921                 return res;
2922 }
2923
2924 MonoObject *
2925 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
2926 {
2927         static MonoMethod *getter = NULL;
2928         MonoDomain *domain = mono_domain_get ();
2929         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
2930         MonoClass *field_class;
2931         MonoMethodMessage *msg;
2932         MonoArray *out_args;
2933         MonoObject *exc, *res;
2934
2935         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
2936
2937         field_class = mono_class_from_mono_type (field->type);
2938
2939         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
2940                 gpointer val;
2941                 if (field_class->valuetype) {
2942                         res = mono_object_new (domain, field_class);
2943                         val = ((gchar *) res) + sizeof (MonoObject);
2944                 } else {
2945                         val = &res;
2946                 }
2947                 mono_field_get_value (tp->rp->unwrapped_server, field, val);
2948                 return res;
2949         }
2950
2951         if (!getter) {
2952                 int i;
2953
2954                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
2955                         MonoMethod *cm = mono_defaults.object_class->methods [i];
2956                
2957                         if (!strcmp (cm->name, "FieldGetter")) {
2958                                 getter = cm;
2959                                 break;
2960                         }
2961                 }
2962                 g_assert (getter);
2963         }
2964         
2965         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
2966         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
2967         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
2968
2969         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
2970         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
2971
2972         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
2973
2974         if (exc) mono_raise_exception ((MonoException *)exc);
2975
2976         res = mono_array_get (out_args, MonoObject *, 0);
2977
2978         return res;
2979 }
2980
2981 /**
2982  * mono_store_remote_field:
2983  * @this: pointer to an object
2984  * @klass: klass of the object containing @field
2985  * @field: the field to load
2986  * @val: the value/object to store
2987  *
2988  * This method is called by the runtime on attempts to store fields of
2989  * transparent proxy objects. @this points to such TP, @klass is the class of
2990  * the object containing @field. @val is the new value to store in @field.
2991  */
2992 void
2993 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
2994 {
2995         static MonoMethod *setter = NULL;
2996         MonoDomain *domain = mono_domain_get ();
2997         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
2998         MonoClass *field_class;
2999         MonoMethodMessage *msg;
3000         MonoArray *out_args;
3001         MonoObject *exc;
3002         MonoObject *arg;
3003
3004         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3005
3006         field_class = mono_class_from_mono_type (field->type);
3007
3008         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3009                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
3010                 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
3011                 return;
3012         }
3013
3014         if (!setter) {
3015                 int i;
3016
3017                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
3018                         MonoMethod *cm = mono_defaults.object_class->methods [i];
3019                
3020                         if (!strcmp (cm->name, "FieldSetter")) {
3021                                 setter = cm;
3022                                 break;
3023                         }
3024                 }
3025                 g_assert (setter);
3026         }
3027
3028         if (field_class->valuetype)
3029                 arg = mono_value_box (domain, field_class, val);
3030         else 
3031                 arg = *((MonoObject **)val);
3032                 
3033
3034         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3035         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
3036
3037         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3038         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3039         mono_array_set (msg->args, gpointer, 2, arg);
3040
3041         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3042
3043         if (exc) mono_raise_exception ((MonoException *)exc);
3044 }
3045
3046 void
3047 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
3048 {
3049         static MonoMethod *setter = NULL;
3050         MonoDomain *domain = mono_domain_get ();
3051         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3052         MonoClass *field_class;
3053         MonoMethodMessage *msg;
3054         MonoArray *out_args;
3055         MonoObject *exc;
3056
3057         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3058
3059         field_class = mono_class_from_mono_type (field->type);
3060
3061         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3062                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
3063                 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
3064                 return;
3065         }
3066
3067         if (!setter) {
3068                 int i;
3069
3070                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
3071                         MonoMethod *cm = mono_defaults.object_class->methods [i];
3072                
3073                         if (!strcmp (cm->name, "FieldSetter")) {
3074                                 setter = cm;
3075                                 break;
3076                         }
3077                 }
3078                 g_assert (setter);
3079         }
3080
3081         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3082         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
3083
3084         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3085         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3086         mono_array_set (msg->args, gpointer, 2, arg);
3087
3088         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3089
3090         if (exc) mono_raise_exception ((MonoException *)exc);
3091 }
3092