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