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