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