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