2008-08-28 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / metadata / object.c
1 /*
2  * object.c: Object creation for the Mono runtime
3  *
4  * Author:
5  *   Miguel de Icaza (miguel@ximian.com)
6  *   Paolo Molaro (lupus@ximian.com)
7  *
8  * (C) 2001-2004 Ximian, Inc.
9  */
10 #include <config.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <signal.h>
14 #include <string.h>
15 #include <mono/metadata/mono-endian.h>
16 #include <mono/metadata/tabledefs.h>
17 #include <mono/metadata/tokentype.h>
18 #include <mono/metadata/loader.h>
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/gc-internal.h>
21 #include <mono/metadata/exception.h>
22 #include <mono/metadata/domain-internals.h>
23 #include "mono/metadata/metadata-internals.h"
24 #include "mono/metadata/class-internals.h"
25 #include <mono/metadata/assembly.h>
26 #include <mono/metadata/threadpool.h>
27 #include <mono/metadata/marshal.h>
28 #include "mono/metadata/debug-helpers.h"
29 #include "mono/metadata/marshal.h"
30 #include <mono/metadata/threads.h>
31 #include <mono/metadata/threads-types.h>
32 #include <mono/metadata/environment.h>
33 #include "mono/metadata/profiler-private.h"
34 #include "mono/metadata/security-manager.h"
35 #include "mono/metadata/mono-debug-debugger.h"
36 #include <mono/metadata/gc-internal.h>
37 #include <mono/utils/strenc.h>
38
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_metdata_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_mempool_alloc0 (domain->mp,  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_mempool_alloc0 (domain->mp, 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_mempool_alloc0 (class->image->mempool, 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_mempool_alloc0 (domain->mp, 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_mempool_alloc0 (domain->mp, 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 mempool MP and return the copy.
1869  */
1870 static gpointer*
1871 copy_remote_class_key (MonoMemPool *mp, gpointer *key)
1872 {
1873         int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
1874         gpointer *mp_key = mono_mempool_alloc (mp, 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->mp, key);
1907         g_free (key);
1908         key = mp_key;
1909
1910         if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1911                 rc = mono_mempool_alloc (domain->mp, 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_mempool_alloc (domain->mp, 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
1925         g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1926
1927         mono_domain_unlock (domain);
1928         return rc;
1929 }
1930
1931 /**
1932  * clone_remote_class:
1933  * Creates a copy of the remote_class, adding the provided class or interface
1934  */
1935 static MonoRemoteClass*
1936 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
1937 {
1938         MonoRemoteClass *rc;
1939         gpointer* key, *mp_key;
1940         
1941         key = create_remote_class_key (remote_class, extra_class);
1942         rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
1943         if (rc != NULL) {
1944                 g_free (key);
1945                 return rc;
1946         }
1947
1948         mp_key = copy_remote_class_key (domain->mp, key);
1949         g_free (key);
1950         key = mp_key;
1951
1952         if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1953                 int i,j;
1954                 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * (remote_class->interface_count + 1));
1955                 rc->proxy_class = remote_class->proxy_class;
1956                 rc->interface_count = remote_class->interface_count + 1;
1957                 
1958                 // Keep the list of interfaces sorted, since the hash key of
1959                 // the remote class depends on this
1960                 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
1961                         if (remote_class->interfaces [i] > extra_class && i == j)
1962                                 rc->interfaces [j++] = extra_class;
1963                         rc->interfaces [j] = remote_class->interfaces [i];
1964                 }
1965                 if (i == j)
1966                         rc->interfaces [j] = extra_class;
1967         } else {
1968                 // Replace the old class. The interface array is the same
1969                 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * remote_class->interface_count);
1970                 rc->proxy_class = extra_class;
1971                 rc->interface_count = remote_class->interface_count;
1972                 if (rc->interface_count > 0)
1973                         memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
1974         }
1975         
1976         rc->default_vtable = NULL;
1977         rc->xdomain_vtable = NULL;
1978         rc->proxy_class_name = remote_class->proxy_class_name;
1979
1980         g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1981
1982         return rc;
1983 }
1984
1985 gpointer
1986 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
1987 {
1988         mono_domain_lock (domain);
1989         if (rp->target_domain_id != -1) {
1990                 if (remote_class->xdomain_vtable == NULL)
1991                         remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
1992                 mono_domain_unlock (domain);
1993                 return remote_class->xdomain_vtable;
1994         }
1995         if (remote_class->default_vtable == NULL) {
1996                 MonoType *type;
1997                 MonoClass *klass;
1998                 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
1999                 klass = mono_class_from_mono_type (type);
2000                 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
2001                         remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
2002                 else
2003                         remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
2004         }
2005         
2006         mono_domain_unlock (domain);
2007         return remote_class->default_vtable;
2008 }
2009
2010 /**
2011  * mono_upgrade_remote_class:
2012  * @domain: the application domain
2013  * @tproxy: the proxy whose remote class has to be upgraded.
2014  * @klass: class to which the remote class can be casted.
2015  *
2016  * Updates the vtable of the remote class by adding the necessary method slots
2017  * and interface offsets so it can be safely casted to klass. klass can be a
2018  * class or an interface.
2019  */
2020 void
2021 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
2022 {
2023         MonoTransparentProxy *tproxy;
2024         MonoRemoteClass *remote_class;
2025         gboolean redo_vtable;
2026
2027         mono_domain_lock (domain);
2028
2029         tproxy = (MonoTransparentProxy*) proxy_object;
2030         remote_class = tproxy->remote_class;
2031         
2032         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2033                 int i;
2034                 redo_vtable = TRUE;
2035                 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
2036                         if (remote_class->interfaces [i] == klass)
2037                                 redo_vtable = FALSE;
2038         }
2039         else {
2040                 redo_vtable = (remote_class->proxy_class != klass);
2041         }
2042
2043         if (redo_vtable) {
2044                 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
2045                 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
2046         }
2047         
2048         mono_domain_unlock (domain);
2049 }
2050
2051
2052 /**
2053  * mono_object_get_virtual_method:
2054  * @obj: object to operate on.
2055  * @method: method 
2056  *
2057  * Retrieves the MonoMethod that would be called on obj if obj is passed as
2058  * the instance of a callvirt of method.
2059  */
2060 MonoMethod*
2061 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
2062 {
2063         MonoClass *klass;
2064         MonoMethod **vtable;
2065         gboolean is_proxy;
2066         MonoMethod *res = NULL;
2067
2068         klass = mono_object_class (obj);
2069         if (klass == mono_defaults.transparent_proxy_class) {
2070                 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2071                 is_proxy = TRUE;
2072         } else {
2073                 is_proxy = FALSE;
2074         }
2075
2076         if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
2077                         return method;
2078
2079         mono_class_setup_vtable (klass);
2080         vtable = klass->vtable;
2081
2082         /* check method->slot is a valid index: perform isinstance? */
2083         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2084                 if (!is_proxy)
2085                        res = vtable [mono_class_interface_offset (klass, method->klass) + method->slot];
2086         } else {
2087                 if (method->slot != -1) {
2088                         res = vtable [method->slot];
2089                 } else {
2090                         /* method->slot might not be set for instances of generic methods in the AOT case */
2091                         if (method->is_inflated) {
2092                                 g_assert (((MonoMethodInflated*)method)->declaring->slot != -1);
2093                                 res = vtable [((MonoMethodInflated*)method)->declaring->slot];
2094                         }
2095                 }
2096         }
2097
2098         if (is_proxy) {
2099                 /* It may be an interface, abstract class method or generic method */
2100                 if (!res || mono_method_signature (res)->generic_param_count)
2101                         res = method;
2102
2103                 /* generic methods demand invoke_with_check */
2104                 if (mono_method_signature (res)->generic_param_count)
2105                         res = mono_marshal_get_remoting_invoke_with_check (res);
2106                 else
2107                         res = mono_marshal_get_remoting_invoke (res);
2108         } else {
2109                 if (method->is_inflated && !res->is_inflated) {
2110                         /* Have to inflate the result */
2111                         res = mono_class_inflate_generic_method (res, &((MonoMethodInflated*)method)->context);
2112                 }
2113         }
2114
2115         g_assert (res);
2116         
2117         return res;
2118 }
2119
2120 static MonoObject*
2121 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2122 {
2123         g_error ("runtime invoke called on uninitialized runtime");
2124         return NULL;
2125 }
2126
2127 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
2128
2129 /**
2130  * mono_runtime_invoke:
2131  * @method: method to invoke
2132  * @obJ: object instance
2133  * @params: arguments to the method
2134  * @exc: exception information.
2135  *
2136  * Invokes the method represented by @method on the object @obj.
2137  *
2138  * obj is the 'this' pointer, it should be NULL for static
2139  * methods, a MonoObject* for object instances and a pointer to
2140  * the value type for value types.
2141  *
2142  * The params array contains the arguments to the method with the
2143  * same convention: MonoObject* pointers for object instances and
2144  * pointers to the value type otherwise. 
2145  * 
2146  * From unmanaged code you'll usually use the
2147  * mono_runtime_invoke() variant.
2148  *
2149  * Note that this function doesn't handle virtual methods for
2150  * you, it will exec the exact method you pass: we still need to
2151  * expose a function to lookup the derived class implementation
2152  * of a virtual method (there are examples of this in the code,
2153  * though).
2154  * 
2155  * You can pass NULL as the exc argument if you don't want to
2156  * catch exceptions, otherwise, *exc will be set to the exception
2157  * thrown, if any.  if an exception is thrown, you can't use the
2158  * MonoObject* result from the function.
2159  * 
2160  * If the method returns a value type, it is boxed in an object
2161  * reference.
2162  */
2163 MonoObject*
2164 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
2165 {
2166         if (mono_runtime_get_no_exec ())
2167                 g_warning ("Invoking method '%s' when running in no-exec mode.\n", mono_method_full_name (method, TRUE));
2168
2169         return default_mono_runtime_invoke (method, obj, params, exc);
2170 }
2171
2172 /**
2173  * mono_method_get_unmanaged_thunk:
2174  * @method: method to generate a thunk for.
2175  *
2176  * Returns an unmanaged->managed thunk that can be used to call
2177  * a managed method directly from C.
2178  *
2179  * The thunk's C signature closely matches the managed signature:
2180  *
2181  * C#: public bool Equals (object obj);
2182  * C:  typedef MonoBoolean (*Equals)(MonoObject*,
2183  *             MonoObject*, MonoException**);
2184  *
2185  * The 1st ("this") parameter must not be used with static methods:
2186  *
2187  * C#: public static bool ReferenceEquals (object a, object b);
2188  * C:  typedef MonoBoolean (*ReferenceEquals)(MonoObject*, MonoObject*,
2189  *             MonoException**);
2190  *
2191  * The last argument must be a non-null pointer of a MonoException* pointer.
2192  * It has "out" semantics. After invoking the thunk, *ex will be NULL if no
2193  * exception has been thrown in managed code. Otherwise it will point
2194  * to the MonoException* caught by the thunk. In this case, the result of
2195  * the thunk is undefined:
2196  *
2197  * MonoMethod *method = ... // MonoMethod* of System.Object.Equals
2198  * MonoException *ex = NULL;
2199  * Equals func = mono_method_get_unmanaged_thunk (method);
2200  * MonoBoolean res = func (thisObj, objToCompare, &ex);
2201  * if (ex) {
2202  *    // handle exception
2203  * }
2204  *
2205  * The calling convention of the thunk matches the platform's default
2206  * convention. This means that under Windows, C declarations must
2207  * contain the __stdcall attribute:
2208  *
2209  * C:  typedef MonoBoolean (__stdcall *Equals)(MonoObject*,
2210  *             MonoObject*, MonoException**);
2211  *
2212  * LIMITATIONS
2213  *
2214  * Value type arguments and return values are treated as they were objects:
2215  *
2216  * C#: public static Rectangle Intersect (Rectangle a, Rectangle b);
2217  * C:  typedef MonoObject* (*Intersect)(MonoObject*, MonoObject*, MonoException**);
2218  *
2219  * Arguments must be properly boxed upon trunk's invocation, while return
2220  * values must be unboxed.
2221  */
2222 gpointer
2223 mono_method_get_unmanaged_thunk (MonoMethod *method)
2224 {
2225         method = mono_marshal_get_thunk_invoke_wrapper (method);
2226         return mono_compile_method (method);
2227 }
2228
2229 static void
2230 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
2231 {
2232         int t;
2233         if (type->byref) {
2234                 gpointer *p = (gpointer*)dest;
2235                 *p = value;
2236                 return;
2237         }
2238         t = type->type;
2239 handle_enum:
2240         switch (t) {
2241         case MONO_TYPE_BOOLEAN:
2242         case MONO_TYPE_I1:
2243         case MONO_TYPE_U1: {
2244                 guint8 *p = (guint8*)dest;
2245                 *p = value ? *(guint8*)value : 0;
2246                 return;
2247         }
2248         case MONO_TYPE_I2:
2249         case MONO_TYPE_U2:
2250         case MONO_TYPE_CHAR: {
2251                 guint16 *p = (guint16*)dest;
2252                 *p = value ? *(guint16*)value : 0;
2253                 return;
2254         }
2255 #if SIZEOF_VOID_P == 4
2256         case MONO_TYPE_I:
2257         case MONO_TYPE_U:
2258 #endif
2259         case MONO_TYPE_I4:
2260         case MONO_TYPE_U4: {
2261                 gint32 *p = (gint32*)dest;
2262                 *p = value ? *(gint32*)value : 0;
2263                 return;
2264         }
2265 #if SIZEOF_VOID_P == 8
2266         case MONO_TYPE_I:
2267         case MONO_TYPE_U:
2268 #endif
2269         case MONO_TYPE_I8:
2270         case MONO_TYPE_U8: {
2271                 gint64 *p = (gint64*)dest;
2272                 *p = value ? *(gint64*)value : 0;
2273                 return;
2274         }
2275         case MONO_TYPE_R4: {
2276                 float *p = (float*)dest;
2277                 *p = value ? *(float*)value : 0;
2278                 return;
2279         }
2280         case MONO_TYPE_R8: {
2281                 double *p = (double*)dest;
2282                 *p = value ? *(double*)value : 0;
2283                 return;
2284         }
2285         case MONO_TYPE_STRING:
2286         case MONO_TYPE_SZARRAY:
2287         case MONO_TYPE_CLASS:
2288         case MONO_TYPE_OBJECT:
2289         case MONO_TYPE_ARRAY:
2290                 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
2291                 return;
2292         case MONO_TYPE_FNPTR:
2293         case MONO_TYPE_PTR: {
2294                 gpointer *p = (gpointer*)dest;
2295                 *p = deref_pointer? *(gpointer*)value: value;
2296                 return;
2297         }
2298         case MONO_TYPE_VALUETYPE:
2299                 /* note that 't' and 'type->type' can be different */
2300                 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
2301                         t = type->data.klass->enum_basetype->type;
2302                         goto handle_enum;
2303                 } else {
2304                         int size;
2305                         size = mono_class_value_size (mono_class_from_mono_type (type), NULL);
2306                         if (value == NULL)
2307                                 memset (dest, 0, size);
2308                         else
2309                                 memcpy (dest, value, size);
2310                 }
2311                 return;
2312         case MONO_TYPE_GENERICINST:
2313                 t = type->data.generic_class->container_class->byval_arg.type;
2314                 goto handle_enum;
2315         default:
2316                 g_warning ("got type %x", type->type);
2317                 g_assert_not_reached ();
2318         }
2319 }
2320
2321 /**
2322  * mono_field_set_value:
2323  * @obj: Instance object
2324  * @field: MonoClassField describing the field to set
2325  * @value: The value to be set
2326  *
2327  * Sets the value of the field described by @field in the object instance @obj
2328  * to the value passed in @value.   This method should only be used for instance
2329  * fields.   For static fields, use mono_field_static_set_value.
2330  *
2331  * The value must be on the native format of the field type. 
2332  */
2333 void
2334 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
2335 {
2336         void *dest;
2337
2338         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2339
2340         dest = (char*)obj + field->offset;
2341         set_value (field->type, dest, value, FALSE);
2342 }
2343
2344 /**
2345  * mono_field_static_set_value:
2346  * @field: MonoClassField describing the field to set
2347  * @value: The value to be set
2348  *
2349  * Sets the value of the static field described by @field
2350  * to the value passed in @value.
2351  *
2352  * The value must be on the native format of the field type. 
2353  */
2354 void
2355 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
2356 {
2357         void *dest;
2358
2359         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2360         /* you cant set a constant! */
2361         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
2362         
2363         dest = (char*)vt->data + field->offset;
2364         set_value (field->type, dest, value, FALSE);
2365 }
2366
2367 /* Used by the debugger */
2368 void *
2369 mono_vtable_get_static_field_data (MonoVTable *vt)
2370 {
2371         return vt->data;
2372 }
2373
2374 /**
2375  * mono_field_get_value:
2376  * @obj: Object instance
2377  * @field: MonoClassField describing the field to fetch information from
2378  * @value: pointer to the location where the value will be stored
2379  *
2380  * Use this routine to get the value of the field @field in the object
2381  * passed.
2382  *
2383  * The pointer provided by value must be of the field type, for reference
2384  * types this is a MonoObject*, for value types its the actual pointer to
2385  * the value type.
2386  *
2387  * For example:
2388  *     int i;
2389  *     mono_field_get_value (obj, int_field, &i);
2390  */
2391 void
2392 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
2393 {
2394         void *src;
2395
2396         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
2397
2398         src = (char*)obj + field->offset;
2399         set_value (field->type, value, src, TRUE);
2400 }
2401
2402 /**
2403  * mono_field_get_value_object:
2404  * @domain: domain where the object will be created (if boxing)
2405  * @field: MonoClassField describing the field to fetch information from
2406  * @obj: The object instance for the field.
2407  *
2408  * Returns: a new MonoObject with the value from the given field.  If the
2409  * field represents a value type, the value is boxed.
2410  *
2411  */
2412 MonoObject *
2413 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
2414 {       
2415         MonoObject *o;
2416         MonoClass *klass;
2417         MonoVTable *vtable = NULL;
2418         gchar *v;
2419         gboolean is_static = FALSE;
2420         gboolean is_ref = FALSE;
2421
2422         switch (field->type->type) {
2423         case MONO_TYPE_STRING:
2424         case MONO_TYPE_OBJECT:
2425         case MONO_TYPE_CLASS:
2426         case MONO_TYPE_ARRAY:
2427         case MONO_TYPE_SZARRAY:
2428                 is_ref = TRUE;
2429                 break;
2430         case MONO_TYPE_U1:
2431         case MONO_TYPE_I1:
2432         case MONO_TYPE_BOOLEAN:
2433         case MONO_TYPE_U2:
2434         case MONO_TYPE_I2:
2435         case MONO_TYPE_CHAR:
2436         case MONO_TYPE_U:
2437         case MONO_TYPE_I:
2438         case MONO_TYPE_U4:
2439         case MONO_TYPE_I4:
2440         case MONO_TYPE_R4:
2441         case MONO_TYPE_U8:
2442         case MONO_TYPE_I8:
2443         case MONO_TYPE_R8:
2444         case MONO_TYPE_VALUETYPE:
2445                 is_ref = field->type->byref;
2446                 break;
2447         case MONO_TYPE_GENERICINST:
2448                 is_ref = !field->type->data.generic_class->container_class->valuetype;
2449                 break;
2450         default:
2451                 g_error ("type 0x%x not handled in "
2452                          "mono_field_get_value_object", field->type->type);
2453                 return NULL;
2454         }
2455
2456         if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
2457                 is_static = TRUE;
2458                 vtable = mono_class_vtable (domain, field->parent);
2459                 if (!vtable->initialized)
2460                         mono_runtime_class_init (vtable);
2461         }
2462         
2463         if (is_ref) {
2464                 if (is_static) {
2465                         mono_field_static_get_value (vtable, field, &o);
2466                 } else {
2467                         mono_field_get_value (obj, field, &o);
2468                 }
2469                 return o;
2470         }
2471
2472         /* boxed value type */
2473         klass = mono_class_from_mono_type (field->type);
2474         o = mono_object_new (domain, klass);
2475         v = ((gchar *) o) + sizeof (MonoObject);
2476         if (is_static) {
2477                 mono_field_static_get_value (vtable, field, v);
2478         } else {
2479                 mono_field_get_value (obj, field, v);
2480         }
2481
2482         return o;
2483 }
2484
2485 int
2486 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
2487 {
2488         int retval = 0;
2489         const char *p = blob;
2490         mono_metadata_decode_blob_size (p, &p);
2491
2492         switch (type) {
2493         case MONO_TYPE_BOOLEAN:
2494         case MONO_TYPE_U1:
2495         case MONO_TYPE_I1:
2496                 *(guint8 *) value = *p;
2497                 break;
2498         case MONO_TYPE_CHAR:
2499         case MONO_TYPE_U2:
2500         case MONO_TYPE_I2:
2501                 *(guint16*) value = read16 (p);
2502                 break;
2503         case MONO_TYPE_U4:
2504         case MONO_TYPE_I4:
2505                 *(guint32*) value = read32 (p);
2506                 break;
2507         case MONO_TYPE_U8:
2508         case MONO_TYPE_I8:
2509                 *(guint64*) value = read64 (p);
2510                 break;
2511         case MONO_TYPE_R4:
2512                 readr4 (p, (float*) value);
2513                 break;
2514         case MONO_TYPE_R8:
2515                 readr8 (p, (double*) value);
2516                 break;
2517         case MONO_TYPE_STRING:
2518                 *(gpointer*) value = mono_ldstr_metdata_sig (domain, blob);
2519                 break;
2520         case MONO_TYPE_CLASS:
2521                 *(gpointer*) value = NULL;
2522                 break;
2523         default:
2524                 retval = -1;
2525                 g_warning ("type 0x%02x should not be in constant table", type);
2526         }
2527         return retval;
2528 }
2529
2530 static void
2531 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
2532 {
2533         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
2534         mono_get_constant_value_from_blob (domain, field->def_type, field->data, value);
2535 }
2536
2537 /**
2538  * mono_field_static_get_value:
2539  * @vt: vtable to the object
2540  * @field: MonoClassField describing the field to fetch information from
2541  * @value: where the value is returned
2542  *
2543  * Use this routine to get the value of the static field @field value.
2544  *
2545  * The pointer provided by value must be of the field type, for reference
2546  * types this is a MonoObject*, for value types its the actual pointer to
2547  * the value type.
2548  *
2549  * For example:
2550  *     int i;
2551  *     mono_field_static_get_value (vt, int_field, &i);
2552  */
2553 void
2554 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
2555 {
2556         void *src;
2557
2558         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
2559         
2560         if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
2561                 get_default_field_value (vt->domain, field, value);
2562                 return;
2563         }
2564
2565         src = (char*)vt->data + field->offset;
2566         set_value (field->type, value, src, TRUE);
2567 }
2568
2569 /**
2570  * mono_property_set_value:
2571  * @prop: MonoProperty to set
2572  * @obj: instance object on which to act
2573  * @params: parameters to pass to the propery
2574  * @exc: optional exception
2575  *
2576  * Invokes the property's set method with the given arguments on the
2577  * object instance obj (or NULL for static properties). 
2578  * 
2579  * You can pass NULL as the exc argument if you don't want to
2580  * catch exceptions, otherwise, *exc will be set to the exception
2581  * thrown, if any.  if an exception is thrown, you can't use the
2582  * MonoObject* result from the function.
2583  */
2584 void
2585 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2586 {
2587         default_mono_runtime_invoke (prop->set, obj, params, exc);
2588 }
2589
2590 /**
2591  * mono_property_get_value:
2592  * @prop: MonoProperty to fetch
2593  * @obj: instance object on which to act
2594  * @params: parameters to pass to the propery
2595  * @exc: optional exception
2596  *
2597  * Invokes the property's get method with the given arguments on the
2598  * object instance obj (or NULL for static properties). 
2599  * 
2600  * You can pass NULL as the exc argument if you don't want to
2601  * catch exceptions, otherwise, *exc will be set to the exception
2602  * thrown, if any.  if an exception is thrown, you can't use the
2603  * MonoObject* result from the function.
2604  *
2605  * Returns: the value from invoking the get method on the property.
2606  */
2607 MonoObject*
2608 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2609 {
2610         return default_mono_runtime_invoke (prop->get, obj, params, exc);
2611 }
2612
2613 /*
2614  * mono_nullable_init:
2615  * @buf: The nullable structure to initialize.
2616  * @value: the value to initialize from
2617  * @klass: the type for the object
2618  *
2619  * Initialize the nullable structure pointed to by @buf from @value which
2620  * should be a boxed value type.   The size of @buf should be able to hold
2621  * as much data as the @klass->instance_size (which is the number of bytes
2622  * that will be copies).
2623  *
2624  * Since Nullables have variable structure, we can not define a C
2625  * structure for them.
2626  */
2627 void
2628 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
2629 {
2630         MonoClass *param_class = klass->cast_class;
2631                                 
2632         g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2633         g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2634
2635         *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
2636         if (value)
2637                 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
2638         else
2639                 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
2640 }
2641
2642 /**
2643  * mono_nullable_box:
2644  * @buf: The buffer representing the data to be boxed
2645  * @klass: the type to box it as.
2646  *
2647  * Creates a boxed vtype or NULL from the Nullable structure pointed to by
2648  * @buf.
2649  */
2650 MonoObject*
2651 mono_nullable_box (guint8 *buf, MonoClass *klass)
2652 {
2653         MonoClass *param_class = klass->cast_class;
2654
2655         g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2656         g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2657
2658         if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
2659                 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
2660                 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
2661                 return o;
2662         }
2663         else
2664                 return NULL;
2665 }
2666
2667 /**
2668  * mono_get_delegate_invoke:
2669  * @klass: The delegate class
2670  *
2671  * Returns: the MonoMethod for the "Invoke" method in the delegate klass
2672  */
2673 MonoMethod *
2674 mono_get_delegate_invoke (MonoClass *klass)
2675 {
2676         MonoMethod *im;
2677
2678         im = mono_class_get_method_from_name (klass, "Invoke", -1);
2679         g_assert (im);
2680
2681         return im;
2682 }
2683
2684 /**
2685  * mono_runtime_delegate_invoke:
2686  * @delegate: pointer to a delegate object.
2687  * @params: parameters for the delegate.
2688  * @exc: Pointer to the exception result.
2689  *
2690  * Invokes the delegate method @delegate with the parameters provided.
2691  *
2692  * You can pass NULL as the exc argument if you don't want to
2693  * catch exceptions, otherwise, *exc will be set to the exception
2694  * thrown, if any.  if an exception is thrown, you can't use the
2695  * MonoObject* result from the function.
2696  */
2697 MonoObject*
2698 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
2699 {
2700         MonoMethod *im;
2701
2702         im = mono_get_delegate_invoke (delegate->vtable->klass);
2703         g_assert (im);
2704
2705         return mono_runtime_invoke (im, delegate, params, exc);
2706 }
2707
2708 static char **main_args = NULL;
2709 static int num_main_args;
2710
2711 /**
2712  * mono_runtime_get_main_args:
2713  *
2714  * Returns: a MonoArray with the arguments passed to the main program
2715  */
2716 MonoArray*
2717 mono_runtime_get_main_args (void)
2718 {
2719         MonoArray *res;
2720         int i;
2721         MonoDomain *domain = mono_domain_get ();
2722
2723         if (!main_args)
2724                 return NULL;
2725
2726         res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
2727
2728         for (i = 0; i < num_main_args; ++i)
2729                 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
2730
2731         return res;
2732 }
2733
2734 static void
2735 fire_process_exit_event (void)
2736 {
2737         MonoClassField *field;
2738         MonoDomain *domain = mono_domain_get ();
2739         gpointer pa [2];
2740         MonoObject *delegate, *exc;
2741         
2742         field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
2743         g_assert (field);
2744
2745         if (domain != mono_get_root_domain ())
2746                 return;
2747
2748         delegate = *(MonoObject **)(((char *)domain->domain) + field->offset); 
2749         if (delegate == NULL)
2750                 return;
2751
2752         pa [0] = domain;
2753         pa [1] = NULL;
2754         mono_runtime_delegate_invoke (delegate, pa, &exc);
2755 }
2756
2757 /**
2758  * mono_runtime_run_main:
2759  * @method: the method to start the application with (usually Main)
2760  * @argc: number of arguments from the command line
2761  * @argv: array of strings from the command line
2762  * @exc: excetption results
2763  *
2764  * Execute a standard Main() method (argc/argv contains the
2765  * executable name). This method also sets the command line argument value
2766  * needed by System.Environment.
2767  *
2768  * 
2769  */
2770 int
2771 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
2772                        MonoObject **exc)
2773 {
2774         int i;
2775         MonoArray *args = NULL;
2776         MonoDomain *domain = mono_domain_get ();
2777         gchar *utf8_fullpath;
2778         int result;
2779
2780         g_assert (method != NULL);
2781         
2782         mono_thread_set_main (mono_thread_current ());
2783
2784         main_args = g_new0 (char*, argc);
2785         num_main_args = argc;
2786
2787         if (!g_path_is_absolute (argv [0])) {
2788                 gchar *basename = g_path_get_basename (argv [0]);
2789                 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
2790                                                     basename,
2791                                                     NULL);
2792
2793                 utf8_fullpath = mono_utf8_from_external (fullpath);
2794                 if(utf8_fullpath == NULL) {
2795                         /* Printing the arg text will cause glib to
2796                          * whinge about "Invalid UTF-8", but at least
2797                          * its relevant, and shows the problem text
2798                          * string.
2799                          */
2800                         g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
2801                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2802                         exit (-1);
2803                 }
2804
2805                 g_free (fullpath);
2806                 g_free (basename);
2807         } else {
2808                 utf8_fullpath = mono_utf8_from_external (argv[0]);
2809                 if(utf8_fullpath == NULL) {
2810                         g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
2811                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2812                         exit (-1);
2813                 }
2814         }
2815
2816         main_args [0] = utf8_fullpath;
2817
2818         for (i = 1; i < argc; ++i) {
2819                 gchar *utf8_arg;
2820
2821                 utf8_arg=mono_utf8_from_external (argv[i]);
2822                 if(utf8_arg==NULL) {
2823                         /* Ditto the comment about Invalid UTF-8 here */
2824                         g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
2825                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2826                         exit (-1);
2827                 }
2828
2829                 main_args [i] = utf8_arg;
2830         }
2831         argc--;
2832         argv++;
2833         if (mono_method_signature (method)->param_count) {
2834                 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
2835                 for (i = 0; i < argc; ++i) {
2836                         /* The encodings should all work, given that
2837                          * we've checked all these args for the
2838                          * main_args array.
2839                          */
2840                         gchar *str = mono_utf8_from_external (argv [i]);
2841                         MonoString *arg = mono_string_new (domain, str);
2842                         mono_array_setref (args, i, arg);
2843                         g_free (str);
2844                 }
2845         } else {
2846                 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
2847         }
2848         
2849         mono_assembly_set_main (method->klass->image->assembly);
2850
2851         result = mono_runtime_exec_main (method, args, exc);
2852         fire_process_exit_event ();
2853         return result;
2854 }
2855
2856 /* Used in call_unhandled_exception_delegate */
2857 static MonoObject *
2858 create_unhandled_exception_eventargs (MonoObject *exc)
2859 {
2860         MonoClass *klass;
2861         gpointer args [2];
2862         MonoMethod *method = NULL;
2863         MonoBoolean is_terminating = TRUE;
2864         MonoObject *obj;
2865
2866         klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
2867         g_assert (klass);
2868
2869         mono_class_init (klass);
2870
2871         /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
2872         method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
2873         g_assert (method);
2874
2875         args [0] = exc;
2876         args [1] = &is_terminating;
2877
2878         obj = mono_object_new (mono_domain_get (), klass);
2879         mono_runtime_invoke (method, obj, args, NULL);
2880
2881         return obj;
2882 }
2883
2884 /* Used in mono_unhandled_exception */
2885 static void
2886 call_unhandled_exception_delegate (MonoDomain *domain, MonoObject *delegate, MonoObject *exc) {
2887         MonoObject *e = NULL;
2888         gpointer pa [2];
2889
2890         pa [0] = domain->domain;
2891         pa [1] = create_unhandled_exception_eventargs (exc);
2892         mono_runtime_delegate_invoke (delegate, pa, &e);
2893         
2894         if (e) {
2895                 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
2896                 g_warning ("exception inside UnhandledException handler: %s\n", msg);
2897                 g_free (msg);
2898         }
2899 }
2900
2901 static MonoRuntimeUnhandledExceptionPolicy runtime_unhandled_exception_policy = MONO_UNHANLED_POLICY_CURRENT;
2902
2903 /**
2904  * mono_runtime_unhandled_exception_policy_set:
2905  * @policy: the new policy
2906  * 
2907  * This is a VM internal routine.
2908  *
2909  * Sets the runtime policy for handling unhandled exceptions.
2910  */
2911 void
2912 mono_runtime_unhandled_exception_policy_set (MonoRuntimeUnhandledExceptionPolicy policy) {
2913         runtime_unhandled_exception_policy = policy;
2914 }
2915
2916 /**
2917  * mono_runtime_unhandled_exception_policy_get:
2918  *
2919  * This is a VM internal routine.
2920  *
2921  * Gets the runtime policy for handling unhandled exceptions.
2922  */
2923 MonoRuntimeUnhandledExceptionPolicy
2924 mono_runtime_unhandled_exception_policy_get (void) {
2925         return runtime_unhandled_exception_policy;
2926 }
2927
2928 /**
2929  * mono_unhandled_exception:
2930  * @exc: exception thrown
2931  *
2932  * This is a VM internal routine.
2933  *
2934  * We call this function when we detect an unhandled exception
2935  * in the default domain.
2936  *
2937  * It invokes the * UnhandledException event in AppDomain or prints
2938  * a warning to the console 
2939  */
2940 void
2941 mono_unhandled_exception (MonoObject *exc)
2942 {
2943         MonoDomain *current_domain = mono_domain_get ();
2944         MonoDomain *root_domain = mono_get_root_domain ();
2945         MonoClassField *field;
2946         MonoObject *current_appdomain_delegate;
2947         MonoObject *root_appdomain_delegate;
2948
2949         field=mono_class_get_field_from_name(mono_defaults.appdomain_class, 
2950                                              "UnhandledException");
2951         g_assert (field);
2952
2953         if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
2954                 gboolean abort_process = (mono_thread_current () == main_thread) ||
2955                                 (mono_runtime_unhandled_exception_policy_get () == MONO_UNHANLED_POLICY_CURRENT);
2956                 root_appdomain_delegate = *(MonoObject **)(((char *)root_domain->domain) + field->offset);
2957                 if (current_domain != root_domain && (mono_get_runtime_info ()->framework_version [0] >= '2')) {
2958                         current_appdomain_delegate = *(MonoObject **)(((char *)current_domain->domain) + field->offset);
2959                 } else {
2960                         current_appdomain_delegate = NULL;
2961                 }
2962
2963                 /* set exitcode only if we will abort the process */
2964                 if (abort_process)
2965                         mono_environment_exitcode_set (1);
2966                 if ((current_appdomain_delegate == NULL) && (root_appdomain_delegate == NULL)) {
2967                         mono_print_unhandled_exception (exc);
2968                 } else {
2969                         if (root_appdomain_delegate) {
2970                                 call_unhandled_exception_delegate (root_domain, root_appdomain_delegate, exc);
2971                         }
2972                         if (current_appdomain_delegate) {
2973                                 call_unhandled_exception_delegate (current_domain, current_appdomain_delegate, exc);
2974                         }
2975                 }
2976         }
2977 }
2978
2979 /*
2980  * Launch a new thread to execute a function
2981  *
2982  * main_func is called back from the thread with main_args as the
2983  * parameter.  The callback function is expected to start Main()
2984  * eventually.  This function then waits for all managed threads to
2985  * finish.
2986  * It is not necesseray anymore to execute managed code in a subthread,
2987  * so this function should not be used anymore by default: just
2988  * execute the code and then call mono_thread_manage ().
2989  */
2990 void
2991 mono_runtime_exec_managed_code (MonoDomain *domain,
2992                                 MonoMainThreadFunc main_func,
2993                                 gpointer main_args)
2994 {
2995         mono_thread_create (domain, main_func, main_args);
2996
2997         mono_thread_manage ();
2998 }
2999
3000 /*
3001  * Execute a standard Main() method (args doesn't contain the
3002  * executable name).
3003  */
3004 int
3005 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
3006 {
3007         MonoDomain *domain;
3008         gpointer pa [1];
3009         int rval;
3010         MonoCustomAttrInfo* cinfo;
3011         gboolean has_stathread_attribute;
3012         MonoThread* thread = mono_thread_current ();
3013
3014         g_assert (args);
3015
3016         pa [0] = args;
3017
3018         domain = mono_object_domain (args);
3019         if (!domain->entry_assembly) {
3020                 gchar *str;
3021                 MonoAssembly *assembly;
3022
3023                 assembly = method->klass->image->assembly;
3024                 domain->entry_assembly = assembly;
3025                 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
3026
3027                 str = g_strconcat (assembly->image->name, ".config", NULL);
3028                 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
3029                 g_free (str);
3030         }
3031
3032         cinfo = mono_custom_attrs_from_method (method);
3033         if (cinfo) {
3034                 static MonoClass *stathread_attribute = NULL;
3035                 if (!stathread_attribute)
3036                         stathread_attribute = mono_class_from_name (mono_defaults.corlib, "System", "STAThreadAttribute");
3037                 has_stathread_attribute = mono_custom_attrs_has_attr (cinfo, stathread_attribute);
3038                 if (!cinfo->cached)
3039                         mono_custom_attrs_free (cinfo);
3040         } else {
3041                 has_stathread_attribute = FALSE;
3042         }
3043         if (has_stathread_attribute) {
3044                 thread->apartment_state = ThreadApartmentState_STA;
3045         } else if (mono_get_runtime_info ()->framework_version [0] == '1') {
3046                 thread->apartment_state = ThreadApartmentState_Unknown;
3047         } else {
3048                 thread->apartment_state = ThreadApartmentState_MTA;
3049         }
3050         mono_thread_init_apartment_state ();
3051
3052         mono_debugger_event (MONO_DEBUGGER_EVENT_REACHED_MAIN, 0, 0);
3053
3054         /* FIXME: check signature of method */
3055         if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
3056                 MonoObject *res;
3057                 res = mono_runtime_invoke (method, NULL, pa, exc);
3058                 if (!exc || !*exc)
3059                         rval = *(guint32 *)((char *)res + sizeof (MonoObject));
3060                 else
3061                         rval = -1;
3062
3063                 mono_environment_exitcode_set (rval);
3064         } else {
3065                 mono_runtime_invoke (method, NULL, pa, exc);
3066                 if (!exc || !*exc)
3067                         rval = 0;
3068                 else {
3069                         /* If the return type of Main is void, only
3070                          * set the exitcode if an exception was thrown
3071                          * (we don't want to blow away an
3072                          * explicitly-set exit code)
3073                          */
3074                         rval = -1;
3075                         mono_environment_exitcode_set (rval);
3076                 }
3077         }
3078
3079         mono_debugger_event (MONO_DEBUGGER_EVENT_MAIN_EXITED, (guint64) (gsize) rval, 0);
3080
3081         return rval;
3082 }
3083
3084 /**
3085  * mono_install_runtime_invoke:
3086  * @func: Function to install
3087  *
3088  * This is a VM internal routine
3089  */
3090 void
3091 mono_install_runtime_invoke (MonoInvokeFunc func)
3092 {
3093         default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
3094 }
3095
3096
3097 /**
3098  * mono_runtime_invoke_array:
3099  * @method: method to invoke
3100  * @obJ: object instance
3101  * @params: arguments to the method
3102  * @exc: exception information.
3103  *
3104  * Invokes the method represented by @method on the object @obj.
3105  *
3106  * obj is the 'this' pointer, it should be NULL for static
3107  * methods, a MonoObject* for object instances and a pointer to
3108  * the value type for value types.
3109  *
3110  * The params array contains the arguments to the method with the
3111  * same convention: MonoObject* pointers for object instances and
3112  * pointers to the value type otherwise. The _invoke_array
3113  * variant takes a C# object[] as the params argument (MonoArray
3114  * *params): in this case the value types are boxed inside the
3115  * respective reference representation.
3116  * 
3117  * From unmanaged code you'll usually use the
3118  * mono_runtime_invoke() variant.
3119  *
3120  * Note that this function doesn't handle virtual methods for
3121  * you, it will exec the exact method you pass: we still need to
3122  * expose a function to lookup the derived class implementation
3123  * of a virtual method (there are examples of this in the code,
3124  * though).
3125  * 
3126  * You can pass NULL as the exc argument if you don't want to
3127  * catch exceptions, otherwise, *exc will be set to the exception
3128  * thrown, if any.  if an exception is thrown, you can't use the
3129  * MonoObject* result from the function.
3130  * 
3131  * If the method returns a value type, it is boxed in an object
3132  * reference.
3133  */
3134 MonoObject*
3135 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
3136                            MonoObject **exc)
3137 {
3138         MonoMethodSignature *sig = mono_method_signature (method);
3139         gpointer *pa = NULL;
3140         int i;
3141
3142         if (NULL != params) {
3143                 pa = alloca (sizeof (gpointer) * mono_array_length (params));
3144                 for (i = 0; i < mono_array_length (params); i++) {
3145                         MonoType *t = sig->params [i];
3146
3147                 again:
3148                         switch (t->type) {
3149                         case MONO_TYPE_U1:
3150                         case MONO_TYPE_I1:
3151                         case MONO_TYPE_BOOLEAN:
3152                         case MONO_TYPE_U2:
3153                         case MONO_TYPE_I2:
3154                         case MONO_TYPE_CHAR:
3155                         case MONO_TYPE_U:
3156                         case MONO_TYPE_I:
3157                         case MONO_TYPE_U4:
3158                         case MONO_TYPE_I4:
3159                         case MONO_TYPE_U8:
3160                         case MONO_TYPE_I8:
3161                         case MONO_TYPE_R4:
3162                         case MONO_TYPE_R8:
3163                         case MONO_TYPE_VALUETYPE:
3164                                 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
3165                                         if (t->byref)
3166                                                 /* FIXME: */
3167                                                 g_assert_not_reached ();
3168                                         /* The runtime invoke wrapper needs the original boxed vtype */
3169                                         pa [i] = mono_array_get (params, MonoObject*, i);
3170                                 } else {
3171                                         /* MS seems to create the objects if a null is passed in */
3172                                         if (!mono_array_get (params, MonoObject*, i))
3173                                                 mono_array_setref (params, i, mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i]))); 
3174
3175                                         if (t->byref) {
3176                                                 /*
3177                                                  * We can't pass the unboxed vtype byref to the callee, since
3178                                                  * that would mean the callee would be able to modify boxed
3179                                                  * primitive types. So we (and MS) make a copy of the boxed
3180                                                  * object, pass that to the callee, and replace the original
3181                                                  * boxed object in the arg array with the copy.
3182                                                  */
3183                                                 MonoObject *orig = mono_array_get (params, MonoObject*, i);
3184                                                 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
3185                                                 mono_array_setref (params, i, copy);
3186                                         }
3187                                                 
3188                                         pa [i] = mono_object_unbox (mono_array_get (params, MonoObject*, i));
3189                                 }
3190                                 break;
3191                         case MONO_TYPE_STRING:
3192                         case MONO_TYPE_OBJECT:
3193                         case MONO_TYPE_CLASS:
3194                         case MONO_TYPE_ARRAY:
3195                         case MONO_TYPE_SZARRAY:
3196                                 if (t->byref)
3197                                         pa [i] = mono_array_addr (params, MonoObject*, i);
3198                                         // FIXME: I need to check this code path
3199                                 else
3200                                         pa [i] = mono_array_get (params, MonoObject*, i);
3201                                 break;
3202                         case MONO_TYPE_GENERICINST:
3203                                 if (t->byref)
3204                                         t = &t->data.generic_class->container_class->this_arg;
3205                                 else
3206                                         t = &t->data.generic_class->container_class->byval_arg;
3207                                 goto again;
3208                         default:
3209                                 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
3210                         }
3211                 }
3212         }
3213
3214         if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
3215                 void *o = obj;
3216
3217                 if (mono_class_is_nullable (method->klass)) {
3218                         /* Need to create a boxed vtype instead */
3219                         g_assert (!obj);
3220
3221                         if (!params)
3222                                 return NULL;
3223                         else
3224                                 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
3225                 }
3226
3227                 if (!obj) {
3228                         obj = mono_object_new (mono_domain_get (), method->klass);
3229                         if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
3230                                 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
3231                         }
3232                         if (method->klass->valuetype)
3233                                 o = mono_object_unbox (obj);
3234                         else
3235                                 o = obj;
3236                 } else if (method->klass->valuetype) {
3237                         obj = mono_value_box (mono_domain_get (), method->klass, obj);
3238                 }
3239
3240                 mono_runtime_invoke (method, o, pa, exc);
3241                 return obj;
3242         } else {
3243                 if (mono_class_is_nullable (method->klass)) {
3244                         MonoObject *nullable;
3245
3246                         /* Convert the unboxed vtype into a Nullable structure */
3247                         nullable = mono_object_new (mono_domain_get (), method->klass);
3248
3249                         mono_nullable_init (mono_object_unbox (nullable), mono_value_box (mono_domain_get (), method->klass->cast_class, obj), method->klass);
3250                         obj = mono_object_unbox (nullable);
3251                 }
3252
3253                 /* obj must be already unboxed if needed */
3254                 return mono_runtime_invoke (method, obj, pa, exc);
3255         }
3256 }
3257
3258 static void
3259 arith_overflow (void)
3260 {
3261         mono_raise_exception (mono_get_exception_overflow ());
3262 }
3263
3264 /**
3265  * mono_object_allocate:
3266  * @size: number of bytes to allocate
3267  *
3268  * This is a very simplistic routine until we have our GC-aware
3269  * memory allocator. 
3270  *
3271  * Returns: an allocated object of size @size, or NULL on failure.
3272  */
3273 static inline void *
3274 mono_object_allocate (size_t size, MonoVTable *vtable)
3275 {
3276         MonoObject *o;
3277         mono_stats.new_object_count++;
3278         ALLOC_OBJECT (o, vtable, size);
3279
3280         return o;
3281 }
3282
3283 /**
3284  * mono_object_allocate_ptrfree:
3285  * @size: number of bytes to allocate
3286  *
3287  * Note that the memory allocated is not zeroed.
3288  * Returns: an allocated object of size @size, or NULL on failure.
3289  */
3290 static inline void *
3291 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
3292 {
3293         MonoObject *o;
3294         mono_stats.new_object_count++;
3295         ALLOC_PTRFREE (o, vtable, size);
3296         return o;
3297 }
3298
3299 static inline void *
3300 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
3301 {
3302         void *o;
3303         ALLOC_TYPED (o, size, vtable);
3304         mono_stats.new_object_count++;
3305
3306         return o;
3307 }
3308
3309 /**
3310  * mono_object_new:
3311  * @klass: the class of the object that we want to create
3312  *
3313  * Returns: a newly created object whose definition is
3314  * looked up using @klass.   This will not invoke any constructors, 
3315  * so the consumer of this routine has to invoke any constructors on
3316  * its own to initialize the object.
3317  */
3318 MonoObject *
3319 mono_object_new (MonoDomain *domain, MonoClass *klass)
3320 {
3321         MONO_ARCH_SAVE_REGS;
3322         return mono_object_new_specific (mono_class_vtable (domain, klass));
3323 }
3324
3325 /**
3326  * mono_object_new_specific:
3327  * @vtable: the vtable of the object that we want to create
3328  *
3329  * Returns: A newly created object with class and domain specified
3330  * by @vtable
3331  */
3332 MonoObject *
3333 mono_object_new_specific (MonoVTable *vtable)
3334 {
3335         MonoObject *o;
3336
3337         MONO_ARCH_SAVE_REGS;
3338         
3339         /* check for is_com_object for COM Interop */
3340         if (vtable->remote || vtable->klass->is_com_object)
3341         {
3342                 gpointer pa [1];
3343                 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
3344
3345                 if (im == NULL) {
3346                         MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
3347
3348                         if (!klass->inited)
3349                                 mono_class_init (klass);
3350
3351                         im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
3352                         g_assert (im);
3353                         vtable->domain->create_proxy_for_type_method = im;
3354                 }
3355         
3356                 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
3357
3358                 o = mono_runtime_invoke (im, NULL, pa, NULL);           
3359                 if (o != NULL) return o;
3360         }
3361
3362         return mono_object_new_alloc_specific (vtable);
3363 }
3364
3365 MonoObject *
3366 mono_object_new_alloc_specific (MonoVTable *vtable)
3367 {
3368         MonoObject *o;
3369
3370         if (!vtable->klass->has_references) {
3371                 o = mono_object_new_ptrfree (vtable);
3372         } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3373                 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
3374         } else {
3375 /*              printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3376                 o = mono_object_allocate (vtable->klass->instance_size, vtable);
3377         }
3378         if (G_UNLIKELY (vtable->klass->has_finalize))
3379                 mono_object_register_finalizer (o);
3380         
3381         if (G_UNLIKELY (profile_allocs))
3382                 mono_profiler_allocation (o, vtable->klass);
3383         return o;
3384 }
3385
3386 MonoObject*
3387 mono_object_new_fast (MonoVTable *vtable)
3388 {
3389         MonoObject *o;
3390         ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
3391         return o;
3392 }
3393
3394 static MonoObject*
3395 mono_object_new_ptrfree (MonoVTable *vtable)
3396 {
3397         MonoObject *obj;
3398         ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3399 #if NEED_TO_ZERO_PTRFREE
3400         /* an inline memset is much faster for the common vcase of small objects
3401          * note we assume the allocated size is a multiple of sizeof (void*).
3402          */
3403         if (vtable->klass->instance_size < 128) {
3404                 gpointer *p, *end;
3405                 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
3406                 p = (gpointer*)((char*)obj + sizeof (MonoObject));
3407                 while (p < end) {
3408                         *p = NULL;
3409                         ++p;
3410                 }
3411         } else {
3412                 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
3413         }
3414 #endif
3415         return obj;
3416 }
3417
3418 static MonoObject*
3419 mono_object_new_ptrfree_box (MonoVTable *vtable)
3420 {
3421         MonoObject *obj;
3422         ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
3423         /* the object will be boxed right away, no need to memzero it */
3424         return obj;
3425 }
3426
3427 /**
3428  * mono_class_get_allocation_ftn:
3429  * @vtable: vtable
3430  * @for_box: the object will be used for boxing
3431  * @pass_size_in_words: 
3432  *
3433  * Return the allocation function appropriate for the given class.
3434  */
3435
3436 void*
3437 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
3438 {
3439         *pass_size_in_words = FALSE;
3440
3441         if (!(mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3442                 profile_allocs = FALSE;
3443
3444         if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
3445                 return mono_object_new_specific;
3446
3447         if (!vtable->klass->has_references) {
3448                 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
3449                 if (for_box)
3450                         return mono_object_new_ptrfree_box;
3451                 return mono_object_new_ptrfree;
3452         }
3453
3454         if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3455
3456                 return mono_object_new_fast;
3457
3458                 /* 
3459                  * FIXME: This is actually slower than mono_object_new_fast, because
3460                  * of the overhead of parameter passing.
3461                  */
3462                 /*
3463                 *pass_size_in_words = TRUE;
3464 #ifdef GC_REDIRECT_TO_LOCAL
3465                 return GC_local_gcj_fast_malloc;
3466 #else
3467                 return GC_gcj_fast_malloc;
3468 #endif
3469                 */
3470         }
3471
3472         return mono_object_new_specific;
3473 }
3474
3475 /**
3476  * mono_object_new_from_token:
3477  * @image: Context where the type_token is hosted
3478  * @token: a token of the type that we want to create
3479  *
3480  * Returns: A newly created object whose definition is
3481  * looked up using @token in the @image image
3482  */
3483 MonoObject *
3484 mono_object_new_from_token  (MonoDomain *domain, MonoImage *image, guint32 token)
3485 {
3486         MonoClass *class;
3487
3488         class = mono_class_get (image, token);
3489
3490         return mono_object_new (domain, class);
3491 }
3492
3493
3494 /**
3495  * mono_object_clone:
3496  * @obj: the object to clone
3497  *
3498  * Returns: A newly created object who is a shallow copy of @obj
3499  */
3500 MonoObject *
3501 mono_object_clone (MonoObject *obj)
3502 {
3503         MonoObject *o;
3504         int size;
3505
3506         size = obj->vtable->klass->instance_size;
3507         o = mono_object_allocate (size, obj->vtable);
3508         /* do not copy the sync state */
3509         memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
3510
3511 #ifdef HAVE_SGEN_GC
3512         if (obj->vtable->klass->has_references)
3513                 mono_gc_wbarrier_object (o);
3514 #endif
3515         if (G_UNLIKELY (profile_allocs))
3516                 mono_profiler_allocation (o, obj->vtable->klass);
3517
3518         if (obj->vtable->klass->has_finalize)
3519                 mono_object_register_finalizer (o);
3520         return o;
3521 }
3522
3523 /**
3524  * mono_array_full_copy:
3525  * @src: source array to copy
3526  * @dest: destination array
3527  *
3528  * Copies the content of one array to another with exactly the same type and size.
3529  */
3530 void
3531 mono_array_full_copy (MonoArray *src, MonoArray *dest)
3532 {
3533         mono_array_size_t size;
3534         MonoClass *klass = src->obj.vtable->klass;
3535
3536         MONO_ARCH_SAVE_REGS;
3537
3538         g_assert (klass == dest->obj.vtable->klass);
3539
3540         size = mono_array_length (src);
3541         g_assert (size == mono_array_length (dest));
3542         size *= mono_array_element_size (klass);
3543 #ifdef HAVE_SGEN_GC
3544         if (klass->element_class->valuetype) {
3545                 if (klass->element_class->has_references)
3546                         mono_value_copy_array (dest, 0, src, mono_array_length (src));
3547                 else
3548                         memcpy (&dest->vector, &src->vector, size);
3549         } else {
3550                 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
3551         }
3552 #else
3553         memcpy (&dest->vector, &src->vector, size);
3554 #endif
3555 }
3556
3557 /**
3558  * mono_array_clone_in_domain:
3559  * @domain: the domain in which the array will be cloned into
3560  * @array: the array to clone
3561  *
3562  * This routine returns a copy of the array that is hosted on the
3563  * specified MonoDomain.
3564  */
3565 MonoArray*
3566 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
3567 {
3568         MonoArray *o;
3569         mono_array_size_t size, i;
3570         mono_array_size_t *sizes;
3571         MonoClass *klass = array->obj.vtable->klass;
3572
3573         MONO_ARCH_SAVE_REGS;
3574
3575         if (array->bounds == NULL) {
3576                 size = mono_array_length (array);
3577                 o = mono_array_new_full (domain, klass, &size, NULL);
3578
3579                 size *= mono_array_element_size (klass);
3580 #ifdef HAVE_SGEN_GC
3581                 if (klass->element_class->valuetype) {
3582                         if (klass->element_class->has_references)
3583                                 mono_value_copy_array (o, 0, array, mono_array_length (array));
3584                         else
3585                                 memcpy (&o->vector, &array->vector, size);
3586                 } else {
3587                         mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3588                 }
3589 #else
3590                 memcpy (&o->vector, &array->vector, size);
3591 #endif
3592                 return o;
3593         }
3594         
3595         sizes = alloca (klass->rank * sizeof(mono_array_size_t) * 2);
3596         size = mono_array_element_size (klass);
3597         for (i = 0; i < klass->rank; ++i) {
3598                 sizes [i] = array->bounds [i].length;
3599                 size *= array->bounds [i].length;
3600                 sizes [i + klass->rank] = array->bounds [i].lower_bound;
3601         }
3602         o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
3603 #ifdef HAVE_SGEN_GC
3604         if (klass->element_class->valuetype) {
3605                 if (klass->element_class->has_references)
3606                         mono_value_copy_array (o, 0, array, mono_array_length (array));
3607                 else
3608                         memcpy (&o->vector, &array->vector, size);
3609         } else {
3610                 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
3611         }
3612 #else
3613         memcpy (&o->vector, &array->vector, size);
3614 #endif
3615
3616         return o;
3617 }
3618
3619 /**
3620  * mono_array_clone:
3621  * @array: the array to clone
3622  *
3623  * Returns: A newly created array who is a shallow copy of @array
3624  */
3625 MonoArray*
3626 mono_array_clone (MonoArray *array)
3627 {
3628         return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
3629 }
3630
3631 /* helper macros to check for overflow when calculating the size of arrays */
3632 #ifdef MONO_BIG_ARRAYS
3633 #define MYGUINT64_MAX 0x0000FFFFFFFFFFFFUL
3634 #define MYGUINT_MAX MYGUINT64_MAX
3635 #define CHECK_ADD_OVERFLOW_UN(a,b) \
3636             (G_UNLIKELY ((guint64)(MYGUINT64_MAX) - (guint64)(b) < (guint64)(a)))
3637 #define CHECK_MUL_OVERFLOW_UN(a,b) \
3638             (G_UNLIKELY (((guint64)(a) > 0) && ((guint64)(b) > 0) &&    \
3639                                          ((guint64)(b) > ((MYGUINT64_MAX) / (guint64)(a)))))
3640 #else
3641 #define MYGUINT32_MAX 4294967295U
3642 #define MYGUINT_MAX MYGUINT32_MAX
3643 #define CHECK_ADD_OVERFLOW_UN(a,b) \
3644             (G_UNLIKELY ((guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a)))
3645 #define CHECK_MUL_OVERFLOW_UN(a,b) \
3646             (G_UNLIKELY (((guint32)(a) > 0) && ((guint32)(b) > 0) &&                    \
3647                                          ((guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a)))))
3648 #endif
3649
3650 /**
3651  * mono_array_new_full:
3652  * @domain: domain where the object is created
3653  * @array_class: array class
3654  * @lengths: lengths for each dimension in the array
3655  * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
3656  *
3657  * This routine creates a new array objects with the given dimensions,
3658  * lower bounds and type.
3659  */
3660 MonoArray*
3661 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, mono_array_size_t *lengths, mono_array_size_t *lower_bounds)
3662 {
3663         mono_array_size_t byte_len, len, bounds_size;
3664         MonoObject *o;
3665         MonoArray *array;
3666         MonoVTable *vtable;
3667         int i;
3668
3669         if (!array_class->inited)
3670                 mono_class_init (array_class);
3671
3672         byte_len = mono_array_element_size (array_class);
3673         len = 1;
3674
3675         /* A single dimensional array with a 0 lower bound is the same as an szarray */
3676         if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
3677                 len = lengths [0];
3678                 if (len > MONO_ARRAY_MAX_INDEX)//MONO_ARRAY_MAX_INDEX
3679                         arith_overflow ();
3680                 bounds_size = 0;
3681         } else {
3682                 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
3683
3684                 for (i = 0; i < array_class->rank; ++i) {
3685                         if (lengths [i] > MONO_ARRAY_MAX_INDEX) //MONO_ARRAY_MAX_INDEX
3686                                 arith_overflow ();
3687                         if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
3688                                 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3689                         len *= lengths [i];
3690                 }
3691         }
3692
3693         if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
3694                 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3695         byte_len *= len;
3696         if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
3697                 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3698         byte_len += sizeof (MonoArray);
3699         if (bounds_size) {
3700                 /* align */
3701                 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
3702                         mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3703                 byte_len = (byte_len + 3) & ~3;
3704                 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
3705                         mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3706                 byte_len += bounds_size;
3707         }
3708         /* 
3709          * Following three lines almost taken from mono_object_new ():
3710          * they need to be kept in sync.
3711          */
3712         vtable = mono_class_vtable (domain, array_class);
3713         if (!array_class->has_references) {
3714                 o = mono_object_allocate_ptrfree (byte_len, vtable);
3715 #if NEED_TO_ZERO_PTRFREE
3716                 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
3717 #endif
3718         } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3719                 o = mono_object_allocate_spec (byte_len, vtable);
3720         }else {
3721                 o = mono_object_allocate (byte_len, vtable);
3722         }
3723
3724         array = (MonoArray*)o;
3725         array->max_length = len;
3726
3727         if (bounds_size) {
3728                 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
3729                 array->bounds = bounds;
3730                 for (i = 0; i < array_class->rank; ++i) {
3731                         bounds [i].length = lengths [i];
3732                         if (lower_bounds)
3733                                 bounds [i].lower_bound = lower_bounds [i];
3734                 }
3735         }
3736
3737         if (G_UNLIKELY (profile_allocs))
3738                 mono_profiler_allocation (o, array_class);
3739
3740         return array;
3741 }
3742
3743 /**
3744  * mono_array_new:
3745  * @domain: domain where the object is created
3746  * @eclass: element class
3747  * @n: number of array elements
3748  *
3749  * This routine creates a new szarray with @n elements of type @eclass.
3750  */
3751 MonoArray *
3752 mono_array_new (MonoDomain *domain, MonoClass *eclass, mono_array_size_t n)
3753 {
3754         MonoClass *ac;
3755
3756         MONO_ARCH_SAVE_REGS;
3757
3758         ac = mono_array_class_get (eclass, 1);
3759         g_assert (ac);
3760
3761         return mono_array_new_specific (mono_class_vtable (domain, ac), n);
3762 }
3763
3764 /**
3765  * mono_array_new_specific:
3766  * @vtable: a vtable in the appropriate domain for an initialized class
3767  * @n: number of array elements
3768  *
3769  * This routine is a fast alternative to mono_array_new() for code which
3770  * can be sure about the domain it operates in.
3771  */
3772 MonoArray *
3773 mono_array_new_specific (MonoVTable *vtable, mono_array_size_t n)
3774 {
3775         MonoObject *o;
3776         MonoArray *ao;
3777         guint32 byte_len, elem_size;
3778
3779         MONO_ARCH_SAVE_REGS;
3780
3781         if (G_UNLIKELY (n > MONO_ARRAY_MAX_INDEX)) {
3782                 arith_overflow ();
3783                 return NULL;
3784         }
3785         
3786         elem_size = mono_array_element_size (vtable->klass);
3787         if (CHECK_MUL_OVERFLOW_UN (n, elem_size)) {
3788                 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3789                 return NULL;
3790         }
3791         byte_len = n * elem_size;
3792         if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray))) {
3793                 mono_gc_out_of_memory (MONO_ARRAY_MAX_SIZE);
3794                 return NULL;
3795         }
3796         byte_len += sizeof (MonoArray);
3797         if (!vtable->klass->has_references) {
3798                 o = mono_object_allocate_ptrfree (byte_len, vtable);
3799 #if NEED_TO_ZERO_PTRFREE
3800                 ((MonoArray*)o)->bounds = NULL;
3801                 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
3802 #endif
3803         } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3804                 o = mono_object_allocate_spec (byte_len, vtable);
3805         } else {
3806 /*              printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3807                 o = mono_object_allocate (byte_len, vtable);
3808         }
3809
3810         ao = (MonoArray *)o;
3811         ao->max_length = n;
3812         if (G_UNLIKELY (profile_allocs))
3813                 mono_profiler_allocation (o, vtable->klass);
3814
3815         return ao;
3816 }
3817
3818 /**
3819  * mono_string_new_utf16:
3820  * @text: a pointer to an utf16 string
3821  * @len: the length of the string
3822  *
3823  * Returns: A newly created string object which contains @text.
3824  */
3825 MonoString *
3826 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
3827 {
3828         MonoString *s;
3829         
3830         s = mono_string_new_size (domain, len);
3831         g_assert (s != NULL);
3832
3833         memcpy (mono_string_chars (s), text, len * 2);
3834
3835         return s;
3836 }
3837
3838 /**
3839  * mono_string_new_size:
3840  * @text: a pointer to an utf16 string
3841  * @len: the length of the string
3842  *
3843  * Returns: A newly created string object of @len
3844  */
3845 MonoString *
3846 mono_string_new_size (MonoDomain *domain, gint32 len)
3847 {
3848         MonoString *s;
3849         MonoVTable *vtable;
3850         size_t size = (sizeof (MonoString) + ((len + 1) * 2));
3851
3852         /* overflow ? can't fit it, can't allocate it! */
3853         if (len > size)
3854                 mono_gc_out_of_memory (-1);
3855
3856         vtable = mono_class_vtable (domain, mono_defaults.string_class);
3857
3858         s = mono_object_allocate_ptrfree (size, vtable);
3859
3860         s->length = len;
3861 #if NEED_TO_ZERO_PTRFREE
3862         s->chars [len] = 0;
3863 #endif
3864         if (G_UNLIKELY (profile_allocs))
3865                 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
3866
3867         return s;
3868 }
3869
3870 /**
3871  * mono_string_new_len:
3872  * @text: a pointer to an utf8 string
3873  * @length: number of bytes in @text to consider
3874  *
3875  * Returns: A newly created string object which contains @text.
3876  */
3877 MonoString*
3878 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
3879 {
3880         GError *error = NULL;
3881         MonoString *o = NULL;
3882         guint16 *ut;
3883         glong items_written;
3884
3885         ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
3886
3887         if (!error)
3888                 o = mono_string_new_utf16 (domain, ut, items_written);
3889         else 
3890                 g_error_free (error);
3891
3892         g_free (ut);
3893
3894         return o;
3895 }
3896
3897 /**
3898  * mono_string_new:
3899  * @text: a pointer to an utf8 string
3900  *
3901  * Returns: A newly created string object which contains @text.
3902  */
3903 MonoString*
3904 mono_string_new (MonoDomain *domain, const char *text)
3905 {
3906     GError *error = NULL;
3907     MonoString *o = NULL;
3908     guint16 *ut;
3909     glong items_written;
3910     int l;
3911
3912     l = strlen (text);
3913    
3914     ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
3915
3916     if (!error)
3917         o = mono_string_new_utf16 (domain, ut, items_written);
3918     else
3919         g_error_free (error);
3920
3921     g_free (ut);
3922 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
3923 #if 0
3924         gunichar2 *str;
3925         const gchar *end;
3926         int len;
3927         MonoString *o = NULL;
3928
3929         if (!g_utf8_validate (text, -1, &end))
3930                 return NULL;
3931
3932         len = g_utf8_strlen (text, -1);
3933         o = mono_string_new_size (domain, len);
3934         str = mono_string_chars (o);
3935
3936         while (text < end) {
3937                 *str++ = g_utf8_get_char (text);
3938                 text = g_utf8_next_char (text);
3939         }
3940 #endif
3941         return o;
3942 }
3943
3944 /**
3945  * mono_string_new_wrapper:
3946  * @text: pointer to utf8 characters.
3947  *
3948  * Helper function to create a string object from @text in the current domain.
3949  */
3950 MonoString*
3951 mono_string_new_wrapper (const char *text)
3952 {
3953         MonoDomain *domain = mono_domain_get ();
3954
3955         MONO_ARCH_SAVE_REGS;
3956
3957         if (text)
3958                 return mono_string_new (domain, text);
3959
3960         return NULL;
3961 }
3962
3963 /**
3964  * mono_value_box:
3965  * @class: the class of the value
3966  * @value: a pointer to the unboxed data
3967  *
3968  * Returns: A newly created object which contains @value.
3969  */
3970 MonoObject *
3971 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
3972 {
3973         MonoObject *res;
3974         int size;
3975         MonoVTable *vtable;
3976
3977         g_assert (class->valuetype);
3978         if (mono_class_is_nullable (class))
3979                 return mono_nullable_box (value, class);
3980
3981         vtable = mono_class_vtable (domain, class);
3982         size = mono_class_instance_size (class);
3983         res = mono_object_new_alloc_specific (vtable);
3984         if (G_UNLIKELY (profile_allocs))
3985                 mono_profiler_allocation (res, class);
3986
3987         size = size - sizeof (MonoObject);
3988
3989 #ifdef HAVE_SGEN_GC
3990         mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
3991 #endif
3992
3993 #if NO_UNALIGNED_ACCESS
3994         memcpy ((char *)res + sizeof (MonoObject), value, size);
3995 #else
3996         switch (size) {
3997         case 1:
3998                 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
3999                 break;
4000         case 2:
4001                 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
4002                 break;
4003         case 4:
4004                 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
4005                 break;
4006         case 8:
4007                 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
4008                 break;
4009         default:
4010                 memcpy ((char *)res + sizeof (MonoObject), value, size);
4011         }
4012 #endif
4013         if (class->has_finalize)
4014                 mono_object_register_finalizer (res);
4015         return res;
4016 }
4017
4018 /*
4019  * mono_value_copy:
4020  * @dest: destination pointer
4021  * @src: source pointer
4022  * @klass: a valuetype class
4023  *
4024  * Copy a valuetype from @src to @dest. This function must be used
4025  * when @klass contains references fields.
4026  */
4027 void
4028 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
4029 {
4030         int size = mono_class_value_size (klass, NULL);
4031         mono_gc_wbarrier_value_copy (dest, src, 1, klass);
4032         memcpy (dest, src, size);
4033 }
4034
4035 /*
4036  * mono_value_copy_array:
4037  * @dest: destination array
4038  * @dest_idx: index in the @dest array
4039  * @src: source pointer
4040  * @count: number of items
4041  *
4042  * Copy @count valuetype items from @src to @dest. This function must be used
4043  * when @klass contains references fields.
4044  * Overlap is handled.
4045  */
4046 void
4047 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
4048 {
4049         int size = mono_array_element_size (dest->obj.vtable->klass);
4050         char *d = mono_array_addr_with_size (dest, size, dest_idx);
4051         mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
4052         memmove (d, src, size * count);
4053 }
4054
4055 /**
4056  * mono_object_get_domain:
4057  * @obj: object to query
4058  * 
4059  * Returns: the MonoDomain where the object is hosted
4060  */
4061 MonoDomain*
4062 mono_object_get_domain (MonoObject *obj)
4063 {
4064         return mono_object_domain (obj);
4065 }
4066
4067 /**
4068  * mono_object_get_class:
4069  * @obj: object to query
4070  * 
4071  * Returns: the MonOClass of the object.
4072  */
4073 MonoClass*
4074 mono_object_get_class (MonoObject *obj)
4075 {
4076         return mono_object_class (obj);
4077 }
4078 /**
4079  * mono_object_get_size:
4080  * @o: object to query
4081  * 
4082  * Returns: the size, in bytes, of @o
4083  */
4084 guint
4085 mono_object_get_size (MonoObject* o)
4086 {
4087         MonoClass* klass = mono_object_class (o);
4088         if (klass == mono_defaults.string_class) {
4089                 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
4090         } else if (o->vtable->rank) {
4091                 MonoArray *array = (MonoArray*)o;
4092                 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
4093                 if (array->bounds) {
4094                         size += 3;
4095                         size &= ~3;
4096                         size += sizeof (MonoArrayBounds) * o->vtable->rank;
4097                 }
4098                 return size;
4099         } else {
4100                 return mono_class_instance_size (klass);
4101         }
4102 }
4103
4104 /**
4105  * mono_object_unbox:
4106  * @obj: object to unbox
4107  * 
4108  * Returns: a pointer to the start of the valuetype boxed in this
4109  * object.
4110  *
4111  * This method will assert if the object passed is not a valuetype.
4112  */
4113 gpointer
4114 mono_object_unbox (MonoObject *obj)
4115 {
4116         /* add assert for valuetypes? */
4117         g_assert (obj->vtable->klass->valuetype);
4118         return ((char*)obj) + sizeof (MonoObject);
4119 }
4120
4121 /**
4122  * mono_object_isinst:
4123  * @obj: an object
4124  * @klass: a pointer to a class 
4125  *
4126  * Returns: @obj if @obj is derived from @klass
4127  */
4128 MonoObject *
4129 mono_object_isinst (MonoObject *obj, MonoClass *klass)
4130 {
4131         if (!klass->inited)
4132                 mono_class_init (klass);
4133
4134         if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) 
4135                 return mono_object_isinst_mbyref (obj, klass);
4136
4137         if (!obj)
4138                 return NULL;
4139
4140         return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
4141 }
4142
4143 MonoObject *
4144 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
4145 {
4146         MonoVTable *vt;
4147
4148         if (!obj)
4149                 return NULL;
4150
4151         vt = obj->vtable;
4152         
4153         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4154                 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
4155                         return obj;
4156                 }
4157         } else {
4158                 MonoClass *oklass = vt->klass;
4159                 if ((oklass == mono_defaults.transparent_proxy_class))
4160                         oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
4161         
4162                 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
4163                         return obj;
4164         }
4165
4166         if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info) 
4167         {
4168                 MonoDomain *domain = mono_domain_get ();
4169                 MonoObject *res;
4170                 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
4171                 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
4172                 MonoMethod *im = NULL;
4173                 gpointer pa [2];
4174
4175                 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
4176                 im = mono_object_get_virtual_method (rp, im);
4177                 g_assert (im);
4178         
4179                 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
4180                 pa [1] = obj;
4181
4182                 res = mono_runtime_invoke (im, rp, pa, NULL);
4183         
4184                 if (*(MonoBoolean *) mono_object_unbox(res)) {
4185                         /* Update the vtable of the remote type, so it can safely cast to this new type */
4186                         mono_upgrade_remote_class (domain, obj, klass);
4187                         return obj;
4188                 }
4189         }
4190
4191         return NULL;
4192 }
4193
4194 /**
4195  * mono_object_castclass_mbyref:
4196  * @obj: an object
4197  * @klass: a pointer to a class 
4198  *
4199  * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
4200  */
4201 MonoObject *
4202 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
4203 {
4204         if (!obj) return NULL;
4205         if (mono_object_isinst_mbyref (obj, klass)) return obj;
4206                 
4207         mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
4208                                                         "System",
4209                                                         "InvalidCastException"));
4210         return NULL;
4211 }
4212
4213 typedef struct {
4214         MonoDomain *orig_domain;
4215         MonoString *ins;
4216         MonoString *res;
4217 } LDStrInfo;
4218
4219 static void
4220 str_lookup (MonoDomain *domain, gpointer user_data)
4221 {
4222         LDStrInfo *info = user_data;
4223         if (info->res || domain == info->orig_domain)
4224                 return;
4225         info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
4226 }
4227
4228 #ifdef HAVE_SGEN_GC
4229
4230 static MonoString*
4231 mono_string_get_pinned (MonoString *str)
4232 {
4233         int size;
4234         MonoString *news;
4235         size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
4236         news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
4237         memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
4238         news->length = mono_string_length (str);
4239         return news;
4240 }
4241
4242 #else
4243 #define mono_string_get_pinned(str) (str)
4244 #endif
4245
4246 static MonoString*
4247 mono_string_is_interned_lookup (MonoString *str, int insert)
4248 {
4249         MonoGHashTable *ldstr_table;
4250         MonoString *res;
4251         MonoDomain *domain;
4252         
4253         domain = ((MonoObject *)str)->vtable->domain;
4254         ldstr_table = domain->ldstr_table;
4255         ldstr_lock ();
4256         if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
4257                 ldstr_unlock ();
4258                 return res;
4259         }
4260         if (insert) {
4261                 str = mono_string_get_pinned (str);
4262                 mono_g_hash_table_insert (ldstr_table, str, str);
4263                 ldstr_unlock ();
4264                 return str;
4265         } else {
4266                 LDStrInfo ldstr_info;
4267                 ldstr_info.orig_domain = domain;
4268                 ldstr_info.ins = str;
4269                 ldstr_info.res = NULL;
4270
4271                 mono_domain_foreach (str_lookup, &ldstr_info);
4272                 if (ldstr_info.res) {
4273                         /* 
4274                          * the string was already interned in some other domain:
4275                          * intern it in the current one as well.
4276                          */
4277                         mono_g_hash_table_insert (ldstr_table, str, str);
4278                         ldstr_unlock ();
4279                         return str;
4280                 }
4281         }
4282         ldstr_unlock ();
4283         return NULL;
4284 }
4285
4286 /**
4287  * mono_string_is_interned:
4288  * @o: String to probe
4289  *
4290  * Returns whether the string has been interned.
4291  */
4292 MonoString*
4293 mono_string_is_interned (MonoString *o)
4294 {
4295         return mono_string_is_interned_lookup (o, FALSE);
4296 }
4297
4298 /**
4299  * mono_string_intern:
4300  * @o: String to intern
4301  *
4302  * Interns the string passed.  
4303  * Returns: The interned string.
4304  */
4305 MonoString*
4306 mono_string_intern (MonoString *str)
4307 {
4308         return mono_string_is_interned_lookup (str, TRUE);
4309 }
4310
4311 /**
4312  * mono_ldstr:
4313  * @domain: the domain where the string will be used.
4314  * @image: a metadata context
4315  * @idx: index into the user string table.
4316  * 
4317  * Implementation for the ldstr opcode.
4318  * Returns: a loaded string from the @image/@idx combination.
4319  */
4320 MonoString*
4321 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
4322 {
4323         MONO_ARCH_SAVE_REGS;
4324
4325         if (image->dynamic)
4326                 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
4327         else
4328                 return mono_ldstr_metdata_sig (domain, mono_metadata_user_string (image, idx));
4329 }
4330
4331 /**
4332  * mono_ldstr_metdata_sig
4333  * @domain: the domain for the string
4334  * @sig: the signature of a metadata string
4335  *
4336  * Returns: a MonoString for a string stored in the metadata
4337  */
4338 static MonoString*
4339 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig)
4340 {
4341         const char *str = sig;
4342         MonoString *o, *interned;
4343         size_t len2;
4344         
4345         len2 = mono_metadata_decode_blob_size (str, &str);
4346         len2 >>= 1;
4347
4348         o = mono_string_new_utf16 (domain, (guint16*)str, len2);
4349 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
4350         {
4351                 int i;
4352                 guint16 *p2 = (guint16*)mono_string_chars (o);
4353                 for (i = 0; i < len2; ++i) {
4354                         *p2 = GUINT16_FROM_LE (*p2);
4355                         ++p2;
4356                 }
4357         }
4358 #endif
4359         ldstr_lock ();
4360         if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
4361                 ldstr_unlock ();
4362                 /* o will get garbage collected */
4363                 return interned;
4364         }
4365
4366         o = mono_string_get_pinned (o);
4367         mono_g_hash_table_insert (domain->ldstr_table, o, o);
4368         ldstr_unlock ();
4369
4370         return o;
4371 }
4372
4373 /**
4374  * mono_string_to_utf8:
4375  * @s: a System.String
4376  *
4377  * Return the UTF8 representation for @s.
4378  * the resulting buffer nedds to be freed with g_free().
4379  */
4380 char *
4381 mono_string_to_utf8 (MonoString *s)
4382 {
4383         long written = 0;
4384         char *as;
4385         GError *error = NULL;
4386
4387         if (s == NULL)
4388                 return NULL;
4389
4390         if (!s->length)
4391                 return g_strdup ("");
4392
4393         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &error);
4394         if (error) {
4395                 MonoException *exc = mono_get_exception_argument ("string", error->message);
4396                 g_error_free (error);
4397                 mono_raise_exception(exc);
4398         }
4399         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
4400         if (s->length > written) {
4401                 /* allocate the total length and copy the part of the string that has been converted */
4402                 char *as2 = g_malloc0 (s->length);
4403                 memcpy (as2, as, written);
4404                 g_free (as);
4405                 as = as2;
4406         }
4407
4408         return as;
4409 }
4410
4411 /**
4412  * mono_string_to_utf16:
4413  * @s: a MonoString
4414  *
4415  * Return an null-terminated array of the utf-16 chars
4416  * contained in @s. The result must be freed with g_free().
4417  * This is a temporary helper until our string implementation
4418  * is reworked to always include the null terminating char.
4419  */
4420 gunichar2 *
4421 mono_string_to_utf16 (MonoString *s)
4422 {
4423         char *as;
4424
4425         if (s == NULL)
4426                 return NULL;
4427
4428         as = g_malloc ((s->length * 2) + 2);
4429         as [(s->length * 2)] = '\0';
4430         as [(s->length * 2) + 1] = '\0';
4431
4432         if (!s->length) {
4433                 return (gunichar2 *)(as);
4434         }
4435         
4436         memcpy (as, mono_string_chars(s), s->length * 2);
4437         return (gunichar2 *)(as);
4438 }
4439
4440 /**
4441  * mono_string_from_utf16:
4442  * @data: the UTF16 string (LPWSTR) to convert
4443  *
4444  * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
4445  *
4446  * Returns: a MonoString.
4447  */
4448 MonoString *
4449 mono_string_from_utf16 (gunichar2 *data)
4450 {
4451         MonoDomain *domain = mono_domain_get ();
4452         int len = 0;
4453
4454         if (!data)
4455                 return NULL;
4456
4457         while (data [len]) len++;
4458
4459         return mono_string_new_utf16 (domain, data, len);
4460 }
4461
4462 /**
4463  * mono_string_to_utf8_mp:
4464  * @s: a System.String
4465  *
4466  * Same as mono_string_to_utf8, but allocate the string from a mempool.
4467  */
4468 char *
4469 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
4470 {
4471         char *r = mono_string_to_utf8 (s);
4472         char *mp_s;
4473         int len;
4474
4475         if (!r)
4476                 return NULL;
4477
4478         len = strlen (r) + 1;
4479         mp_s = mono_mempool_alloc (mp, len);
4480         memcpy (mp_s, r, len);
4481
4482         g_free (r);
4483
4484         return mp_s;
4485 }
4486
4487 static void
4488 default_ex_handler (MonoException *ex)
4489 {
4490         MonoObject *o = (MonoObject*)ex;
4491         g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
4492         exit (1);
4493 }
4494
4495 static MonoExceptionFunc ex_handler = default_ex_handler;
4496
4497 /**
4498  * mono_install_handler:
4499  * @func: exception handler
4500  *
4501  * This is an internal JIT routine used to install the handler for exceptions
4502  * being throwh.
4503  */
4504 void
4505 mono_install_handler (MonoExceptionFunc func)
4506 {
4507         ex_handler = func? func: default_ex_handler;
4508 }
4509
4510 /**
4511  * mono_raise_exception:
4512  * @ex: exception object
4513  *
4514  * Signal the runtime that the exception @ex has been raised in unmanaged code.
4515  */
4516 void
4517 mono_raise_exception (MonoException *ex) 
4518 {
4519         /*
4520          * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
4521          * that will cause gcc to omit the function epilog, causing problems when
4522          * the JIT tries to walk the stack, since the return address on the stack
4523          * will point into the next function in the executable, not this one.
4524          */
4525
4526         if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class)
4527                 MONO_OBJECT_SETREF (mono_thread_current (), abort_exc, ex);
4528         
4529         ex_handler (ex);
4530 }
4531
4532 /**
4533  * mono_wait_handle_new:
4534  * @domain: Domain where the object will be created
4535  * @handle: Handle for the wait handle
4536  *
4537  * Returns: A new MonoWaitHandle created in the given domain for the given handle
4538  */
4539 MonoWaitHandle *
4540 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
4541 {
4542         MonoWaitHandle *res;
4543         gpointer params [1];
4544         static MonoMethod *handle_set;
4545
4546         res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
4547
4548         /* Even though this method is virtual, it's safe to invoke directly, since the object type matches.  */
4549         if (!handle_set)
4550                 handle_set = mono_class_get_property_from_name (mono_defaults.waithandle_class, "Handle")->set;
4551
4552         params [0] = &handle;
4553         mono_runtime_invoke (handle_set, res, params, NULL);
4554
4555         return res;
4556 }
4557
4558 HANDLE
4559 mono_wait_handle_get_handle (MonoWaitHandle *handle)
4560 {
4561         static MonoClassField *f_os_handle;
4562         static MonoClassField *f_safe_handle;
4563
4564         if (!f_os_handle && !f_safe_handle) {
4565                 f_os_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "os_handle");
4566                 f_safe_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "safe_wait_handle");
4567         }
4568
4569         if (f_os_handle) {
4570                 HANDLE retval;
4571                 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
4572                 return retval;
4573         } else {
4574                 MonoSafeHandle *sh;
4575                 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
4576                 return sh->handle;
4577         }
4578 }
4579
4580 /**
4581  * mono_async_result_new:
4582  * @domain:domain where the object will be created.
4583  * @handle: wait handle.
4584  * @state: state to pass to AsyncResult
4585  * @data: C closure data.
4586  *
4587  * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
4588  * If the handle is not null, the handle is initialized to a MonOWaitHandle.
4589  *
4590  */
4591 MonoAsyncResult *
4592 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
4593 {
4594         MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
4595         MonoMethod *method = mono_get_context_capture_method ();
4596
4597         /* we must capture the execution context from the original thread */
4598         if (method) {
4599                 MONO_OBJECT_SETREF (res, execution_context, mono_runtime_invoke (method, NULL, NULL, NULL));
4600                 /* note: result may be null if the flow is suppressed */
4601         }
4602
4603         res->data = data;
4604         MONO_OBJECT_SETREF (res, object_data, object_data);
4605         MONO_OBJECT_SETREF (res, async_state, state);
4606         if (handle != NULL)
4607                 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
4608
4609         res->sync_completed = FALSE;
4610         res->completed = FALSE;
4611
4612         return res;
4613 }
4614
4615 void
4616 mono_message_init (MonoDomain *domain,
4617                    MonoMethodMessage *this, 
4618                    MonoReflectionMethod *method,
4619                    MonoArray *out_args)
4620 {
4621         static MonoClass *object_array_klass;
4622         static MonoClass *byte_array_klass;
4623         static MonoClass *string_array_klass;
4624         MonoMethodSignature *sig = mono_method_signature (method->method);
4625         MonoString *name;
4626         int i, j;
4627         char **names;
4628         guint8 arg_type;
4629
4630         if (!object_array_klass) {
4631                 MonoClass *klass;
4632
4633                 klass = mono_array_class_get (mono_defaults.object_class, 1);
4634                 g_assert (klass);
4635
4636                 mono_memory_barrier ();
4637                 object_array_klass = klass;
4638
4639                 klass = mono_array_class_get (mono_defaults.byte_class, 1);
4640                 g_assert (klass);
4641
4642                 mono_memory_barrier ();
4643                 byte_array_klass = klass;
4644
4645                 klass = mono_array_class_get (mono_defaults.string_class, 1);
4646                 g_assert (klass);
4647
4648                 mono_memory_barrier ();
4649                 string_array_klass = klass;
4650         }
4651
4652         MONO_OBJECT_SETREF (this, method, method);
4653
4654         MONO_OBJECT_SETREF (this, args, mono_array_new_specific (mono_class_vtable (domain, object_array_klass), sig->param_count));
4655         MONO_OBJECT_SETREF (this, arg_types, mono_array_new_specific (mono_class_vtable (domain, byte_array_klass), sig->param_count));
4656         this->async_result = NULL;
4657         this->call_type = CallType_Sync;
4658
4659         names = g_new (char *, sig->param_count);
4660         mono_method_get_param_names (method->method, (const char **) names);
4661         MONO_OBJECT_SETREF (this, names, mono_array_new_specific (mono_class_vtable (domain, string_array_klass), sig->param_count));
4662         
4663         for (i = 0; i < sig->param_count; i++) {
4664                 name = mono_string_new (domain, names [i]);
4665                 mono_array_setref (this->names, i, name);       
4666         }
4667
4668         g_free (names);
4669         for (i = 0, j = 0; i < sig->param_count; i++) {
4670                 if (sig->params [i]->byref) {
4671                         if (out_args) {
4672                                 MonoObject* arg = mono_array_get (out_args, gpointer, j);
4673                                 mono_array_setref (this->args, i, arg);
4674                                 j++;
4675                         }
4676                         arg_type = 2;
4677                         if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
4678                                 arg_type |= 1;
4679                 } else {
4680                         arg_type = 1;
4681                         if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
4682                                 arg_type |= 4;
4683                 }
4684                 mono_array_set (this->arg_types, guint8, i, arg_type);
4685         }
4686 }
4687
4688 /**
4689  * mono_remoting_invoke:
4690  * @real_proxy: pointer to a RealProxy object
4691  * @msg: The MonoMethodMessage to execute
4692  * @exc: used to store exceptions
4693  * @out_args: used to store output arguments
4694  *
4695  * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
4696  * IMessage interface and it is not trivial to extract results from there. So
4697  * we call an helper method PrivateInvoke instead of calling
4698  * RealProxy::Invoke() directly.
4699  *
4700  * Returns: the result object.
4701  */
4702 MonoObject *
4703 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, 
4704                       MonoObject **exc, MonoArray **out_args)
4705 {
4706         MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
4707         gpointer pa [4];
4708
4709         /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
4710
4711         if (!im) {
4712                 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
4713                 g_assert (im);
4714                 real_proxy->vtable->domain->private_invoke_method = im;
4715         }
4716
4717         pa [0] = real_proxy;
4718         pa [1] = msg;
4719         pa [2] = exc;
4720         pa [3] = out_args;
4721
4722         return mono_runtime_invoke (im, NULL, pa, exc);
4723 }
4724
4725 MonoObject *
4726 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
4727                      MonoObject **exc, MonoArray **out_args) 
4728 {
4729         static MonoClass *object_array_klass;
4730         MonoDomain *domain; 
4731         MonoMethod *method;
4732         MonoMethodSignature *sig;
4733         MonoObject *ret;
4734         int i, j, outarg_count = 0;
4735
4736         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
4737
4738                 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
4739                 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4740                         target = tp->rp->unwrapped_server;
4741                 } else {
4742                         return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
4743                 }
4744         }
4745
4746         domain = mono_domain_get (); 
4747         method = msg->method->method;
4748         sig = mono_method_signature (method);
4749
4750         for (i = 0; i < sig->param_count; i++) {
4751                 if (sig->params [i]->byref) 
4752                         outarg_count++;
4753         }
4754
4755         if (!object_array_klass) {
4756                 MonoClass *klass;
4757
4758                 klass = mono_array_class_get (mono_defaults.object_class, 1);
4759                 g_assert (klass);
4760
4761                 mono_memory_barrier ();
4762                 object_array_klass = klass;
4763         }
4764
4765         /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
4766         *out_args = mono_array_new_specific (mono_class_vtable (domain, object_array_klass), outarg_count);
4767         *exc = NULL;
4768
4769         ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
4770
4771         for (i = 0, j = 0; i < sig->param_count; i++) {
4772                 if (sig->params [i]->byref) {
4773                         MonoObject* arg;
4774                         arg = mono_array_get (msg->args, gpointer, i);
4775                         mono_array_setref (*out_args, j, arg);
4776                         j++;
4777                 }
4778         }
4779
4780         return ret;
4781 }
4782
4783 /**
4784  * mono_print_unhandled_exception:
4785  * @exc: The exception
4786  *
4787  * Prints the unhandled exception.
4788  */
4789 void
4790 mono_print_unhandled_exception (MonoObject *exc)
4791 {
4792         char *message = (char *) "";
4793         MonoString *str; 
4794         MonoMethod *method;
4795         MonoClass *klass;
4796         gboolean free_message = FALSE;
4797
4798         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
4799                 klass = exc->vtable->klass;
4800                 method = NULL;
4801                 while (klass && method == NULL) {
4802                         method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
4803                         if (method == NULL)
4804                                 klass = klass->parent;
4805                 }
4806
4807                 g_assert (method);
4808
4809                 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
4810                 if (str) {
4811                         message = mono_string_to_utf8 (str);
4812                         free_message = TRUE;
4813                 }
4814         }                               
4815
4816         /*
4817          * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space, 
4818          *         exc->vtable->klass->name, message);
4819          */
4820         g_printerr ("\nUnhandled Exception: %s\n", message);
4821         
4822         if (free_message)
4823                 g_free (message);
4824 }
4825
4826 /**
4827  * mono_delegate_ctor:
4828  * @this: pointer to an uninitialized delegate object
4829  * @target: target object
4830  * @addr: pointer to native code
4831  * @method: method
4832  *
4833  * Initialize a delegate and sets a specific method, not the one
4834  * associated with addr.  This is useful when sharing generic code.
4835  * In that case addr will most probably not be associated with the
4836  * correct instantiation of the method.
4837  */
4838 void
4839 mono_delegate_ctor_with_method (MonoObject *this, MonoObject *target, gpointer addr, MonoMethod *method)
4840 {
4841         MonoDelegate *delegate = (MonoDelegate *)this;
4842         MonoClass *class;
4843
4844         g_assert (this);
4845         g_assert (addr);
4846
4847         if (method)
4848                 delegate->method = method;
4849
4850         class = this->vtable->klass;
4851         mono_stats.delegate_creations++;
4852
4853         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
4854                 g_assert (method);
4855                 method = mono_marshal_get_remoting_invoke (method);
4856                 delegate->method_ptr = mono_compile_method (method);
4857                 MONO_OBJECT_SETREF (delegate, target, target);
4858         } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
4859                 method = mono_marshal_get_unbox_wrapper (method);
4860                 delegate->method_ptr = mono_compile_method (method);
4861                 MONO_OBJECT_SETREF (delegate, target, target);
4862         } else {
4863                 delegate->method_ptr = addr;
4864                 MONO_OBJECT_SETREF (delegate, target, target);
4865         }
4866
4867         delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->klass);
4868 }
4869
4870 /**
4871  * mono_delegate_ctor:
4872  * @this: pointer to an uninitialized delegate object
4873  * @target: target object
4874  * @addr: pointer to native code
4875  *
4876  * This is used to initialize a delegate.
4877  */
4878 void
4879 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
4880 {
4881         MonoDomain *domain = mono_domain_get ();
4882         MonoJitInfo *ji;
4883         MonoMethod *method = NULL;
4884
4885         g_assert (addr);
4886
4887         if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
4888                 method = ji->method;
4889                 g_assert (!method->klass->generic_container);
4890         }
4891
4892         mono_delegate_ctor_with_method (this, target, addr, method);
4893 }
4894
4895 /**
4896  * mono_method_call_message_new:
4897  * @method: method to encapsulate
4898  * @params: parameters to the method
4899  * @invoke: optional, delegate invoke.
4900  * @cb: async callback delegate.
4901  * @state: state passed to the async callback.
4902  *
4903  * Translates arguments pointers into a MonoMethodMessage.
4904  */
4905 MonoMethodMessage *
4906 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke, 
4907                               MonoDelegate **cb, MonoObject **state)
4908 {
4909         MonoDomain *domain = mono_domain_get ();
4910         MonoMethodSignature *sig = mono_method_signature (method);
4911         MonoMethodMessage *msg;
4912         int i, count, type;
4913
4914         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class); 
4915         
4916         if (invoke) {
4917                 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
4918                 count =  sig->param_count - 2;
4919         } else {
4920                 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
4921                 count =  sig->param_count;
4922         }
4923
4924         for (i = 0; i < count; i++) {
4925                 gpointer vpos;
4926                 MonoClass *class;
4927                 MonoObject *arg;
4928
4929                 if (sig->params [i]->byref)
4930                         vpos = *((gpointer *)params [i]);
4931                 else 
4932                         vpos = params [i];
4933
4934                 type = sig->params [i]->type;
4935                 class = mono_class_from_mono_type (sig->params [i]);
4936
4937                 if (class->valuetype)
4938                         arg = mono_value_box (domain, class, vpos);
4939                 else 
4940                         arg = *((MonoObject **)vpos);
4941                       
4942                 mono_array_setref (msg->args, i, arg);
4943         }
4944
4945         if (cb != NULL && state != NULL) {
4946                 *cb = *((MonoDelegate **)params [i]);
4947                 i++;
4948                 *state = *((MonoObject **)params [i]);
4949         }
4950
4951         return msg;
4952 }
4953
4954 /**
4955  * mono_method_return_message_restore:
4956  *
4957  * Restore results from message based processing back to arguments pointers
4958  */
4959 void
4960 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
4961 {
4962         MonoMethodSignature *sig = mono_method_signature (method);
4963         int i, j, type, size, out_len;
4964         
4965         if (out_args == NULL)
4966                 return;
4967         out_len = mono_array_length (out_args);
4968         if (out_len == 0)
4969                 return;
4970
4971         for (i = 0, j = 0; i < sig->param_count; i++) {
4972                 MonoType *pt = sig->params [i];
4973
4974                 if (pt->byref) {
4975                         char *arg;
4976                         if (j >= out_len)
4977                                 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
4978
4979                         arg = mono_array_get (out_args, gpointer, j);
4980                         type = pt->type;
4981
4982                         switch (type) {
4983                         case MONO_TYPE_VOID:
4984                                 g_assert_not_reached ();
4985                                 break;
4986                         case MONO_TYPE_U1:
4987                         case MONO_TYPE_I1:
4988                         case MONO_TYPE_BOOLEAN:
4989                         case MONO_TYPE_U2:
4990                         case MONO_TYPE_I2:
4991                         case MONO_TYPE_CHAR:
4992                         case MONO_TYPE_U4:
4993                         case MONO_TYPE_I4:
4994                         case MONO_TYPE_I8:
4995                         case MONO_TYPE_U8:
4996                         case MONO_TYPE_R4:
4997                         case MONO_TYPE_R8:
4998                         case MONO_TYPE_VALUETYPE: {
4999                                 if (arg) {
5000                                         size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
5001                                         memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size); 
5002                                 }
5003                                 else {
5004                                         size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
5005                                         memset (*((gpointer *)params [i]), 0, size);
5006                                 }
5007                                 break;
5008                         }
5009                         case MONO_TYPE_STRING:
5010                         case MONO_TYPE_CLASS: 
5011                         case MONO_TYPE_ARRAY:
5012                         case MONO_TYPE_SZARRAY:
5013                         case MONO_TYPE_OBJECT:
5014                                 **((MonoObject ***)params [i]) = (MonoObject *)arg;
5015                                 break;
5016                         default:
5017                                 g_assert_not_reached ();
5018                         }
5019
5020                         j++;
5021                 }
5022         }
5023 }
5024
5025 /**
5026  * mono_load_remote_field:
5027  * @this: pointer to an object
5028  * @klass: klass of the object containing @field
5029  * @field: the field to load
5030  * @res: a storage to store the result
5031  *
5032  * This method is called by the runtime on attempts to load fields of
5033  * transparent proxy objects. @this points to such TP, @klass is the class of
5034  * the object containing @field. @res is a storage location which can be
5035  * used to store the result.
5036  *
5037  * Returns: an address pointing to the value of field.
5038  */
5039 gpointer
5040 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
5041 {
5042         static MonoMethod *getter = NULL;
5043         MonoDomain *domain = mono_domain_get ();
5044         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5045         MonoClass *field_class;
5046         MonoMethodMessage *msg;
5047         MonoArray *out_args;
5048         MonoObject *exc;
5049         char* full_name;
5050
5051         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5052         g_assert (res != NULL);
5053
5054         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5055                 mono_field_get_value (tp->rp->unwrapped_server, field, res);
5056                 return res;
5057         }
5058         
5059         if (!getter) {
5060                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5061                 g_assert (getter);
5062         }
5063         
5064         field_class = mono_class_from_mono_type (field->type);
5065
5066         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5067         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5068         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5069
5070         full_name = mono_type_get_full_name (klass);
5071         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5072         mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
5073         g_free (full_name);
5074
5075         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5076
5077         if (exc) mono_raise_exception ((MonoException *)exc);
5078
5079         if (mono_array_length (out_args) == 0)
5080                 return NULL;
5081
5082         *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
5083
5084         if (field_class->valuetype) {
5085                 return ((char *)*res) + sizeof (MonoObject);
5086         } else
5087                 return res;
5088 }
5089
5090 /**
5091  * mono_load_remote_field_new:
5092  * @this: 
5093  * @klass: 
5094  * @field:
5095  *
5096  * Missing documentation.
5097  */
5098 MonoObject *
5099 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
5100 {
5101         static MonoMethod *getter = NULL;
5102         MonoDomain *domain = mono_domain_get ();
5103         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5104         MonoClass *field_class;
5105         MonoMethodMessage *msg;
5106         MonoArray *out_args;
5107         MonoObject *exc, *res;
5108         char* full_name;
5109
5110         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5111
5112         field_class = mono_class_from_mono_type (field->type);
5113
5114         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5115                 gpointer val;
5116                 if (field_class->valuetype) {
5117                         res = mono_object_new (domain, field_class);
5118                         val = ((gchar *) res) + sizeof (MonoObject);
5119                 } else {
5120                         val = &res;
5121                 }
5122                 mono_field_get_value (tp->rp->unwrapped_server, field, val);
5123                 return res;
5124         }
5125
5126         if (!getter) {
5127                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
5128                 g_assert (getter);
5129         }
5130         
5131         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5132         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
5133
5134         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
5135
5136         full_name = mono_type_get_full_name (klass);
5137         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5138         mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
5139         g_free (full_name);
5140
5141         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5142
5143         if (exc) mono_raise_exception ((MonoException *)exc);
5144
5145         if (mono_array_length (out_args) == 0)
5146                 res = NULL;
5147         else
5148                 res = mono_array_get (out_args, MonoObject *, 0);
5149
5150         return res;
5151 }
5152
5153 /**
5154  * mono_store_remote_field:
5155  * @this: pointer to an object
5156  * @klass: klass of the object containing @field
5157  * @field: the field to load
5158  * @val: the value/object to store
5159  *
5160  * This method is called by the runtime on attempts to store fields of
5161  * transparent proxy objects. @this points to such TP, @klass is the class of
5162  * the object containing @field. @val is the new value to store in @field.
5163  */
5164 void
5165 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
5166 {
5167         static MonoMethod *setter = NULL;
5168         MonoDomain *domain = mono_domain_get ();
5169         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5170         MonoClass *field_class;
5171         MonoMethodMessage *msg;
5172         MonoArray *out_args;
5173         MonoObject *exc;
5174         MonoObject *arg;
5175         char* full_name;
5176
5177         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5178
5179         field_class = mono_class_from_mono_type (field->type);
5180
5181         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5182                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
5183                 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
5184                 return;
5185         }
5186
5187         if (!setter) {
5188                 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5189                 g_assert (setter);
5190         }
5191
5192         if (field_class->valuetype)
5193                 arg = mono_value_box (domain, field_class, val);
5194         else 
5195                 arg = *((MonoObject **)val);
5196                 
5197
5198         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5199         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5200
5201         full_name = mono_type_get_full_name (klass);
5202         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5203         mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
5204         mono_array_setref (msg->args, 2, arg);
5205         g_free (full_name);
5206
5207         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5208
5209         if (exc) mono_raise_exception ((MonoException *)exc);
5210 }
5211
5212 /**
5213  * mono_store_remote_field_new:
5214  * @this:
5215  * @klass:
5216  * @field:
5217  * @arg:
5218  *
5219  * Missing documentation
5220  */
5221 void
5222 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
5223 {
5224         static MonoMethod *setter = NULL;
5225         MonoDomain *domain = mono_domain_get ();
5226         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
5227         MonoClass *field_class;
5228         MonoMethodMessage *msg;
5229         MonoArray *out_args;
5230         MonoObject *exc;
5231         char* full_name;
5232
5233         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
5234
5235         field_class = mono_class_from_mono_type (field->type);
5236
5237         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
5238                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
5239                 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
5240                 return;
5241         }
5242
5243         if (!setter) {
5244                 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
5245                 g_assert (setter);
5246         }
5247
5248         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
5249         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
5250
5251         full_name = mono_type_get_full_name (klass);
5252         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
5253         mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
5254         mono_array_setref (msg->args, 2, arg);
5255         g_free (full_name);
5256
5257         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
5258
5259         if (exc) mono_raise_exception ((MonoException *)exc);
5260 }
5261
5262 /*
5263  * mono_create_ftnptr:
5264  *
5265  *   Given a function address, create a function descriptor for it.
5266  * This is only needed on IA64 and PPC64.
5267  */
5268 gpointer
5269 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
5270 {
5271 #ifdef __ia64__
5272         gpointer *desc;
5273
5274         mono_domain_lock (domain);
5275         desc = mono_code_manager_reserve (domain->code_mp, 2 * sizeof (gpointer));
5276         mono_domain_unlock (domain);
5277
5278         desc [0] = addr;
5279         desc [1] = NULL;
5280
5281         return desc;
5282 #elif defined(__ppc64__) || defined(__powerpc64__)
5283         gpointer *desc;
5284
5285         mono_domain_lock (domain);
5286         desc = mono_code_manager_reserve (domain->code_mp, 3 * sizeof (gpointer));
5287         mono_domain_unlock (domain);
5288
5289         desc [0] = addr;
5290         desc [1] = NULL;
5291         desc [2] = NULL;
5292
5293         return desc;
5294 #else
5295         return addr;
5296 #endif
5297 }
5298
5299 /*
5300  * mono_get_addr_from_ftnptr:
5301  *
5302  *   Given a pointer to a function descriptor, return the function address.
5303  * This is only needed on IA64 and PPC64.
5304  */
5305 gpointer
5306 mono_get_addr_from_ftnptr (gpointer descr)
5307 {
5308 #if defined(__ia64__) || defined(__ppc64__) || defined(__powerpc64__)
5309         return *(gpointer*)descr;
5310 #else
5311         return descr;
5312 #endif
5313 }       
5314
5315 #if 0
5316 /**
5317  * mono_string_chars:
5318  * @s: a MonoString
5319  *
5320  * Returns a pointer to the UCS16 characters stored in the MonoString
5321  */
5322 gunichar2 *
5323 mono_string_chars(MonoString *s)
5324 {
5325         /* This method is here only for documentation extraction, this is a macro */
5326 }
5327
5328 /**
5329  * mono_string_length:
5330  * @s: MonoString
5331  *
5332  * Returns the lenght in characters of the string
5333  */
5334 int
5335 mono_string_length (MonoString *s)
5336 {
5337         /* This method is here only for documentation extraction, this is a macro */
5338 }
5339
5340 #endif