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