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