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