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