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