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