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