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