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