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