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