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