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