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