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