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