[runtime] Use MonoError for mono_string_new_utf16
[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 *res = NULL;
5167         res = mono_string_new_utf16_checked (domain, text, len, &error);
5168         mono_error_raise_exception (&error);
5169
5170         return res;
5171 }
5172
5173 /**
5174  * mono_string_new_utf16_checked:
5175  * @text: a pointer to an utf16 string
5176  * @len: the length of the string
5177  * @error: written on error.
5178  *
5179  * Returns: A newly created string object which contains @text.
5180  * On error, returns NULL and sets @error.
5181  */
5182 MonoString *
5183 mono_string_new_utf16_checked (MonoDomain *domain, const guint16 *text, gint32 len, MonoError *error)
5184 {
5185         MONO_REQ_GC_UNSAFE_MODE;
5186
5187         MonoString *s;
5188         
5189         mono_error_init (error);
5190         
5191         s = mono_string_new_size_checked (domain, len, error);
5192         if (s != NULL)
5193                 memcpy (mono_string_chars (s), text, len * 2);
5194
5195         return s;
5196 }
5197
5198 /**
5199  * mono_string_new_utf32:
5200  * @text: a pointer to an utf32 string
5201  * @len: the length of the string
5202  *
5203  * Returns: A newly created string object which contains @text.
5204  */
5205 MonoString *
5206 mono_string_new_utf32 (MonoDomain *domain, const mono_unichar4 *text, gint32 len)
5207 {
5208         MONO_REQ_GC_UNSAFE_MODE;
5209
5210         MonoError error;
5211         MonoString *s;
5212         mono_unichar2 *utf16_output = NULL;
5213         gint32 utf16_len = 0;
5214         GError *gerror = NULL;
5215         glong items_written;
5216         
5217         utf16_output = g_ucs4_to_utf16 (text, len, NULL, &items_written, &gerror);
5218         
5219         if (gerror)
5220                 g_error_free (gerror);
5221
5222         while (utf16_output [utf16_len]) utf16_len++;
5223         
5224         s = mono_string_new_size_checked (domain, utf16_len, &error);
5225         mono_error_raise_exception (&error); /* FIXME don't raise here */
5226
5227         memcpy (mono_string_chars (s), utf16_output, utf16_len * 2);
5228
5229         g_free (utf16_output);
5230         
5231         return s;
5232 }
5233
5234 /**
5235  * mono_string_new_size:
5236  * @text: a pointer to an utf16 string
5237  * @len: the length of the string
5238  *
5239  * Returns: A newly created string object of @len
5240  */
5241 MonoString *
5242 mono_string_new_size (MonoDomain *domain, gint32 len)
5243 {
5244         MonoError error;
5245         MonoString *str = mono_string_new_size_checked (domain, len, &error);
5246         mono_error_raise_exception (&error);
5247
5248         return str;
5249 }
5250
5251 MonoString *
5252 mono_string_new_size_checked (MonoDomain *domain, gint32 len, MonoError *error)
5253 {
5254         MONO_REQ_GC_UNSAFE_MODE;
5255
5256         MonoString *s;
5257         MonoVTable *vtable;
5258         size_t size;
5259
5260         mono_error_init (error);
5261
5262         /* check for overflow */
5263         if (len < 0 || len > ((SIZE_MAX - G_STRUCT_OFFSET (MonoString, chars) - 8) / 2)) {
5264                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", -1);
5265                 return NULL;
5266         }
5267
5268         size = (G_STRUCT_OFFSET (MonoString, chars) + (((size_t)len + 1) * 2));
5269         g_assert (size > 0);
5270
5271         vtable = mono_class_vtable (domain, mono_defaults.string_class);
5272         g_assert (vtable);
5273
5274         s = (MonoString *)mono_gc_alloc_string (vtable, size, len);
5275
5276         if (G_UNLIKELY (!s)) {
5277                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5278                 return NULL;
5279         }
5280
5281         return s;
5282 }
5283
5284 /**
5285  * mono_string_new_len:
5286  * @text: a pointer to an utf8 string
5287  * @length: number of bytes in @text to consider
5288  *
5289  * Returns: A newly created string object which contains @text.
5290  */
5291 MonoString*
5292 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
5293 {
5294         MONO_REQ_GC_UNSAFE_MODE;
5295
5296         GError *error = NULL;
5297         MonoString *o = NULL;
5298         guint16 *ut;
5299         glong items_written;
5300
5301         ut = eg_utf8_to_utf16_with_nuls (text, length, NULL, &items_written, &error);
5302
5303         if (!error)
5304                 o = mono_string_new_utf16 (domain, ut, items_written);
5305         else 
5306                 g_error_free (error);
5307
5308         g_free (ut);
5309
5310         return o;
5311 }
5312
5313 /**
5314  * mono_string_new:
5315  * @text: a pointer to an utf8 string
5316  *
5317  * Returns: A newly created string object which contains @text.
5318  */
5319 MonoString*
5320 mono_string_new (MonoDomain *domain, const char *text)
5321 {
5322         MONO_REQ_GC_UNSAFE_MODE;
5323
5324     GError *error = NULL;
5325     MonoString *o = NULL;
5326     guint16 *ut;
5327     glong items_written;
5328     int l;
5329
5330     l = strlen (text);
5331    
5332     ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
5333
5334     if (!error)
5335         o = mono_string_new_utf16 (domain, ut, items_written);
5336     else
5337         g_error_free (error);
5338
5339     g_free (ut);
5340 /*FIXME g_utf8_get_char, g_utf8_next_char and g_utf8_validate are not part of eglib.*/
5341 #if 0
5342         MonoError error;
5343         gunichar2 *str;
5344         const gchar *end;
5345         int len;
5346         MonoString *o = NULL;
5347
5348         if (!g_utf8_validate (text, -1, &end))
5349                 return NULL;
5350
5351         len = g_utf8_strlen (text, -1);
5352         o = mono_string_new_size_checked (domain, len, &error);
5353         mono_error_raise_exception (&error); /* FIXME don't raise here */
5354         str = mono_string_chars (o);
5355
5356         while (text < end) {
5357                 *str++ = g_utf8_get_char (text);
5358                 text = g_utf8_next_char (text);
5359         }
5360 #endif
5361         return o;
5362 }
5363
5364 /**
5365  * mono_string_new_wrapper:
5366  * @text: pointer to utf8 characters.
5367  *
5368  * Helper function to create a string object from @text in the current domain.
5369  */
5370 MonoString*
5371 mono_string_new_wrapper (const char *text)
5372 {
5373         MONO_REQ_GC_UNSAFE_MODE;
5374
5375         MonoDomain *domain = mono_domain_get ();
5376
5377         if (text)
5378                 return mono_string_new (domain, text);
5379
5380         return NULL;
5381 }
5382
5383 /**
5384  * mono_value_box:
5385  * @class: the class of the value
5386  * @value: a pointer to the unboxed data
5387  *
5388  * Returns: A newly created object which contains @value.
5389  */
5390 MonoObject *
5391 mono_value_box (MonoDomain *domain, MonoClass *klass, gpointer value)
5392 {
5393         MONO_REQ_GC_UNSAFE_MODE;
5394
5395         MonoError error;
5396         MonoObject *res;
5397         int size;
5398         MonoVTable *vtable;
5399
5400         g_assert (klass->valuetype);
5401         if (mono_class_is_nullable (klass))
5402                 return mono_nullable_box ((guint8 *)value, klass);
5403
5404         vtable = mono_class_vtable (domain, klass);
5405         if (!vtable)
5406                 return NULL;
5407         size = mono_class_instance_size (klass);
5408         res = mono_object_new_alloc_specific_checked (vtable, &error);
5409         mono_error_raise_exception (&error); /* FIXME don't raise here */
5410
5411         size = size - sizeof (MonoObject);
5412
5413 #ifdef HAVE_SGEN_GC
5414         g_assert (size == mono_class_value_size (klass, NULL));
5415         mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, klass);
5416 #else
5417 #if NO_UNALIGNED_ACCESS
5418         mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5419 #else
5420         switch (size) {
5421         case 1:
5422                 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
5423                 break;
5424         case 2:
5425                 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
5426                 break;
5427         case 4:
5428                 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
5429                 break;
5430         case 8:
5431                 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
5432                 break;
5433         default:
5434                 mono_gc_memmove_atomic ((char *)res + sizeof (MonoObject), value, size);
5435         }
5436 #endif
5437 #endif
5438         if (klass->has_finalize)
5439                 mono_object_register_finalizer (res);
5440         return res;
5441 }
5442
5443 /*
5444  * mono_value_copy:
5445  * @dest: destination pointer
5446  * @src: source pointer
5447  * @klass: a valuetype class
5448  *
5449  * Copy a valuetype from @src to @dest. This function must be used
5450  * when @klass contains references fields.
5451  */
5452 void
5453 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
5454 {
5455         MONO_REQ_GC_UNSAFE_MODE;
5456
5457         mono_gc_wbarrier_value_copy (dest, src, 1, klass);
5458 }
5459
5460 /*
5461  * mono_value_copy_array:
5462  * @dest: destination array
5463  * @dest_idx: index in the @dest array
5464  * @src: source pointer
5465  * @count: number of items
5466  *
5467  * Copy @count valuetype items from @src to the array @dest at index @dest_idx. 
5468  * This function must be used when @klass contains references fields.
5469  * Overlap is handled.
5470  */
5471 void
5472 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
5473 {
5474         MONO_REQ_GC_UNSAFE_MODE;
5475
5476         int size = mono_array_element_size (dest->obj.vtable->klass);
5477         char *d = mono_array_addr_with_size_fast (dest, size, dest_idx);
5478         g_assert (size == mono_class_value_size (mono_object_class (dest)->element_class, NULL));
5479         mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
5480 }
5481
5482 /**
5483  * mono_object_get_domain:
5484  * @obj: object to query
5485  * 
5486  * Returns: the MonoDomain where the object is hosted
5487  */
5488 MonoDomain*
5489 mono_object_get_domain (MonoObject *obj)
5490 {
5491         MONO_REQ_GC_UNSAFE_MODE;
5492
5493         return mono_object_domain (obj);
5494 }
5495
5496 /**
5497  * mono_object_get_class:
5498  * @obj: object to query
5499  * 
5500  * Returns: the MonOClass of the object.
5501  */
5502 MonoClass*
5503 mono_object_get_class (MonoObject *obj)
5504 {
5505         MONO_REQ_GC_UNSAFE_MODE;
5506
5507         return mono_object_class (obj);
5508 }
5509 /**
5510  * mono_object_get_size:
5511  * @o: object to query
5512  * 
5513  * Returns: the size, in bytes, of @o
5514  */
5515 guint
5516 mono_object_get_size (MonoObject* o)
5517 {
5518         MONO_REQ_GC_UNSAFE_MODE;
5519
5520         MonoClass* klass = mono_object_class (o);
5521         if (klass == mono_defaults.string_class) {
5522                 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
5523         } else if (o->vtable->rank) {
5524                 MonoArray *array = (MonoArray*)o;
5525                 size_t size = MONO_SIZEOF_MONO_ARRAY + mono_array_element_size (klass) * mono_array_length (array);
5526                 if (array->bounds) {
5527                         size += 3;
5528                         size &= ~3;
5529                         size += sizeof (MonoArrayBounds) * o->vtable->rank;
5530                 }
5531                 return size;
5532         } else {
5533                 return mono_class_instance_size (klass);
5534         }
5535 }
5536
5537 /**
5538  * mono_object_unbox:
5539  * @obj: object to unbox
5540  * 
5541  * Returns: a pointer to the start of the valuetype boxed in this
5542  * object.
5543  *
5544  * This method will assert if the object passed is not a valuetype.
5545  */
5546 gpointer
5547 mono_object_unbox (MonoObject *obj)
5548 {
5549         MONO_REQ_GC_UNSAFE_MODE;
5550
5551         /* add assert for valuetypes? */
5552         g_assert (obj->vtable->klass->valuetype);
5553         return ((char*)obj) + sizeof (MonoObject);
5554 }
5555
5556 /**
5557  * mono_object_isinst:
5558  * @obj: an object
5559  * @klass: a pointer to a class 
5560  *
5561  * Returns: @obj if @obj is derived from @klass
5562  */
5563 MonoObject *
5564 mono_object_isinst (MonoObject *obj, MonoClass *klass)
5565 {
5566         MONO_REQ_GC_UNSAFE_MODE;
5567
5568         if (!klass->inited)
5569                 mono_class_init (klass);
5570
5571         if (mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_INTERFACE))
5572                 return mono_object_isinst_mbyref (obj, klass);
5573
5574         if (!obj)
5575                 return NULL;
5576
5577         return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
5578 }
5579
5580 MonoObject *
5581 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
5582 {
5583         MONO_REQ_GC_UNSAFE_MODE;
5584
5585         MonoError error;
5586         MonoVTable *vt;
5587
5588         if (!obj)
5589                 return NULL;
5590
5591         vt = obj->vtable;
5592         
5593         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
5594                 if (MONO_VTABLE_IMPLEMENTS_INTERFACE (vt, klass->interface_id)) {
5595                         return obj;
5596                 }
5597
5598                 /*If the above check fails we are in the slow path of possibly raising an exception. So it's ok to it this way.*/
5599                 if (mono_class_has_variant_generic_params (klass) && mono_class_is_assignable_from (klass, obj->vtable->klass))
5600                         return obj;
5601         } else {
5602                 MonoClass *oklass = vt->klass;
5603                 if (mono_class_is_transparent_proxy (oklass))
5604                         oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
5605
5606                 mono_class_setup_supertypes (klass);    
5607                 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
5608                         return obj;
5609         }
5610 #ifndef DISABLE_REMOTING
5611         if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info) 
5612         {
5613                 MonoDomain *domain = mono_domain_get ();
5614                 MonoObject *res;
5615                 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
5616                 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
5617                 MonoMethod *im = NULL;
5618                 gpointer pa [2];
5619
5620                 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
5621                 if (!im)
5622                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
5623                 im = mono_object_get_virtual_method (rp, im);
5624                 g_assert (im);
5625         
5626                 pa [0] = mono_type_get_object_checked (domain, &klass->byval_arg, &error);
5627                 mono_error_raise_exception (&error); /* FIXME don't raise here */
5628                 pa [1] = obj;
5629
5630                 res = mono_runtime_invoke (im, rp, pa, NULL);
5631         
5632                 if (*(MonoBoolean *) mono_object_unbox(res)) {
5633                         /* Update the vtable of the remote type, so it can safely cast to this new type */
5634                         mono_upgrade_remote_class (domain, obj, klass);
5635                         return obj;
5636                 }
5637         }
5638 #endif /* DISABLE_REMOTING */
5639         return NULL;
5640 }
5641
5642 /**
5643  * mono_object_castclass_mbyref:
5644  * @obj: an object
5645  * @klass: a pointer to a class 
5646  *
5647  * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
5648  */
5649 MonoObject *
5650 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
5651 {
5652         MONO_REQ_GC_UNSAFE_MODE;
5653
5654         if (!obj) return NULL;
5655         if (mono_object_isinst_mbyref (obj, klass)) return obj;
5656                 
5657         mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
5658                                                         "System",
5659                                                         "InvalidCastException"));
5660         return NULL;
5661 }
5662
5663 typedef struct {
5664         MonoDomain *orig_domain;
5665         MonoString *ins;
5666         MonoString *res;
5667 } LDStrInfo;
5668
5669 static void
5670 str_lookup (MonoDomain *domain, gpointer user_data)
5671 {
5672         MONO_REQ_GC_UNSAFE_MODE;
5673
5674         LDStrInfo *info = (LDStrInfo *)user_data;
5675         if (info->res || domain == info->orig_domain)
5676                 return;
5677         info->res = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
5678 }
5679
5680 static MonoString*
5681 mono_string_get_pinned (MonoString *str, MonoError *error)
5682 {
5683         MONO_REQ_GC_UNSAFE_MODE;
5684
5685         mono_error_init (error);
5686
5687         /* We only need to make a pinned version of a string if this is a moving GC */
5688         if (!mono_gc_is_moving ())
5689                 return str;
5690         int size;
5691         MonoString *news;
5692         size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
5693         news = (MonoString *)mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
5694         if (news) {
5695                 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
5696                 news->length = mono_string_length (str);
5697         } else {
5698                 mono_error_set_out_of_memory (error, "Could not allocate %i bytes", size);
5699         }
5700         return news;
5701 }
5702
5703 static MonoString*
5704 mono_string_is_interned_lookup (MonoString *str, int insert)
5705 {
5706         MONO_REQ_GC_UNSAFE_MODE;
5707
5708         MonoError error;
5709         MonoGHashTable *ldstr_table;
5710         MonoString *s, *res;
5711         MonoDomain *domain;
5712         
5713         domain = ((MonoObject *)str)->vtable->domain;
5714         ldstr_table = domain->ldstr_table;
5715         ldstr_lock ();
5716         res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
5717         if (res) {
5718                 ldstr_unlock ();
5719                 return res;
5720         }
5721         if (insert) {
5722                 /* Allocate outside the lock */
5723                 ldstr_unlock ();
5724                 s = mono_string_get_pinned (str, &error);
5725                 mono_error_raise_exception (&error); /* FIXME don't raise here */
5726                 if (s) {
5727                         ldstr_lock ();
5728                         res = (MonoString *)mono_g_hash_table_lookup (ldstr_table, str);
5729                         if (res) {
5730                                 ldstr_unlock ();
5731                                 return res;
5732                         }
5733                         mono_g_hash_table_insert (ldstr_table, s, s);
5734                         ldstr_unlock ();
5735                 }
5736                 return s;
5737         } else {
5738                 LDStrInfo ldstr_info;
5739                 ldstr_info.orig_domain = domain;
5740                 ldstr_info.ins = str;
5741                 ldstr_info.res = NULL;
5742
5743                 mono_domain_foreach (str_lookup, &ldstr_info);
5744                 if (ldstr_info.res) {
5745                         /* 
5746                          * the string was already interned in some other domain:
5747                          * intern it in the current one as well.
5748                          */
5749                         mono_g_hash_table_insert (ldstr_table, str, str);
5750                         ldstr_unlock ();
5751                         return str;
5752                 }
5753         }
5754         ldstr_unlock ();
5755         return NULL;
5756 }
5757
5758 /**
5759  * mono_string_is_interned:
5760  * @o: String to probe
5761  *
5762  * Returns whether the string has been interned.
5763  */
5764 MonoString*
5765 mono_string_is_interned (MonoString *o)
5766 {
5767         MONO_REQ_GC_UNSAFE_MODE;
5768
5769         return mono_string_is_interned_lookup (o, FALSE);
5770 }
5771
5772 /**
5773  * mono_string_intern:
5774  * @o: String to intern
5775  *
5776  * Interns the string passed.  
5777  * Returns: The interned string.
5778  */
5779 MonoString*
5780 mono_string_intern (MonoString *str)
5781 {
5782         MONO_REQ_GC_UNSAFE_MODE;
5783
5784         return mono_string_is_interned_lookup (str, TRUE);
5785 }
5786
5787 /**
5788  * mono_ldstr:
5789  * @domain: the domain where the string will be used.
5790  * @image: a metadata context
5791  * @idx: index into the user string table.
5792  * 
5793  * Implementation for the ldstr opcode.
5794  * Returns: a loaded string from the @image/@idx combination.
5795  */
5796 MonoString*
5797 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
5798 {
5799         MONO_REQ_GC_UNSAFE_MODE;
5800
5801         if (image->dynamic) {
5802                 MonoString *str = (MonoString *)mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx, NULL);
5803                 return str;
5804         } else {
5805                 if (!mono_verifier_verify_string_signature (image, idx, NULL))
5806                         return NULL; /*FIXME we should probably be raising an exception here*/
5807                 return mono_ldstr_metadata_sig (domain, mono_metadata_user_string (image, idx));
5808         }
5809 }
5810
5811 /**
5812  * mono_ldstr_metadata_sig
5813  * @domain: the domain for the string
5814  * @sig: the signature of a metadata string
5815  *
5816  * Returns: a MonoString for a string stored in the metadata
5817  */
5818 static MonoString*
5819 mono_ldstr_metadata_sig (MonoDomain *domain, const char* sig)
5820 {
5821         MONO_REQ_GC_UNSAFE_MODE;
5822
5823         MonoError error;
5824         const char *str = sig;
5825         MonoString *o, *interned;
5826         size_t len2;
5827
5828         len2 = mono_metadata_decode_blob_size (str, &str);
5829         len2 >>= 1;
5830
5831         o = mono_string_new_utf16 (domain, (guint16*)str, len2);
5832 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
5833         {
5834                 int i;
5835                 guint16 *p2 = (guint16*)mono_string_chars (o);
5836                 for (i = 0; i < len2; ++i) {
5837                         *p2 = GUINT16_FROM_LE (*p2);
5838                         ++p2;
5839                 }
5840         }
5841 #endif
5842         ldstr_lock ();
5843         interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
5844         ldstr_unlock ();
5845         if (interned)
5846                 return interned; /* o will get garbage collected */
5847
5848         o = mono_string_get_pinned (o, &error);
5849         mono_error_raise_exception (&error); /* FIXME don't raise here */
5850         if (o) {
5851                 ldstr_lock ();
5852                 interned = (MonoString *)mono_g_hash_table_lookup (domain->ldstr_table, o);
5853                 if (!interned) {
5854                         mono_g_hash_table_insert (domain->ldstr_table, o, o);
5855                         interned = o;
5856                 }
5857                 ldstr_unlock ();
5858         }
5859
5860         return interned;
5861 }
5862
5863 /**
5864  * mono_string_to_utf8:
5865  * @s: a System.String
5866  *
5867  * Returns the UTF8 representation for @s.
5868  * The resulting buffer needs to be freed with mono_free().
5869  *
5870  * @deprecated Use mono_string_to_utf8_checked to avoid having an exception arbritraly raised.
5871  */
5872 char *
5873 mono_string_to_utf8 (MonoString *s)
5874 {
5875         MONO_REQ_GC_UNSAFE_MODE;
5876
5877         MonoError error;
5878         char *result = mono_string_to_utf8_checked (s, &error);
5879         
5880         if (!mono_error_ok (&error))
5881                 mono_error_raise_exception (&error);
5882         return result;
5883 }
5884
5885 /**
5886  * mono_string_to_utf8_checked:
5887  * @s: a System.String
5888  * @error: a MonoError.
5889  * 
5890  * Converts a MonoString to its UTF8 representation. May fail; check 
5891  * @error to determine whether the conversion was successful.
5892  * The resulting buffer should be freed with mono_free().
5893  */
5894 char *
5895 mono_string_to_utf8_checked (MonoString *s, MonoError *error)
5896 {
5897         MONO_REQ_GC_UNSAFE_MODE;
5898
5899         long written = 0;
5900         char *as;
5901         GError *gerror = NULL;
5902
5903         mono_error_init (error);
5904
5905         if (s == NULL)
5906                 return NULL;
5907
5908         if (!s->length)
5909                 return g_strdup ("");
5910
5911         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, &gerror);
5912         if (gerror) {
5913                 mono_error_set_argument (error, "string", "%s", gerror->message);
5914                 g_error_free (gerror);
5915                 return NULL;
5916         }
5917         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5918         if (s->length > written) {
5919                 /* allocate the total length and copy the part of the string that has been converted */
5920                 char *as2 = (char *)g_malloc0 (s->length);
5921                 memcpy (as2, as, written);
5922                 g_free (as);
5923                 as = as2;
5924         }
5925
5926         return as;
5927 }
5928
5929 /**
5930  * mono_string_to_utf8_ignore:
5931  * @s: a MonoString
5932  *
5933  * Converts a MonoString to its UTF8 representation. Will ignore
5934  * invalid surrogate pairs.
5935  * The resulting buffer should be freed with mono_free().
5936  * 
5937  */
5938 char *
5939 mono_string_to_utf8_ignore (MonoString *s)
5940 {
5941         MONO_REQ_GC_UNSAFE_MODE;
5942
5943         long written = 0;
5944         char *as;
5945
5946         if (s == NULL)
5947                 return NULL;
5948
5949         if (!s->length)
5950                 return g_strdup ("");
5951
5952         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, &written, NULL);
5953
5954         /* g_utf16_to_utf8  may not be able to complete the convertion (e.g. NULL values were found, #335488) */
5955         if (s->length > written) {
5956                 /* allocate the total length and copy the part of the string that has been converted */
5957                 char *as2 = (char *)g_malloc0 (s->length);
5958                 memcpy (as2, as, written);
5959                 g_free (as);
5960                 as = as2;
5961         }
5962
5963         return as;
5964 }
5965
5966 /**
5967  * mono_string_to_utf8_image_ignore:
5968  * @s: a System.String
5969  *
5970  * Same as mono_string_to_utf8_ignore, but allocate the string from the image mempool.
5971  */
5972 char *
5973 mono_string_to_utf8_image_ignore (MonoImage *image, MonoString *s)
5974 {
5975         MONO_REQ_GC_UNSAFE_MODE;
5976
5977         return mono_string_to_utf8_internal (NULL, image, s, TRUE, NULL);
5978 }
5979
5980 /**
5981  * mono_string_to_utf8_mp_ignore:
5982  * @s: a System.String
5983  *
5984  * Same as mono_string_to_utf8_ignore, but allocate the string from a mempool.
5985  */
5986 char *
5987 mono_string_to_utf8_mp_ignore (MonoMemPool *mp, MonoString *s)
5988 {
5989         MONO_REQ_GC_UNSAFE_MODE;
5990
5991         return mono_string_to_utf8_internal (mp, NULL, s, TRUE, NULL);
5992 }
5993
5994
5995 /**
5996  * mono_string_to_utf16:
5997  * @s: a MonoString
5998  *
5999  * Return an null-terminated array of the utf-16 chars
6000  * contained in @s. The result must be freed with g_free().
6001  * This is a temporary helper until our string implementation
6002  * is reworked to always include the null terminating char.
6003  */
6004 mono_unichar2*
6005 mono_string_to_utf16 (MonoString *s)
6006 {
6007         MONO_REQ_GC_UNSAFE_MODE;
6008
6009         char *as;
6010
6011         if (s == NULL)
6012                 return NULL;
6013
6014         as = (char *)g_malloc ((s->length * 2) + 2);
6015         as [(s->length * 2)] = '\0';
6016         as [(s->length * 2) + 1] = '\0';
6017
6018         if (!s->length) {
6019                 return (gunichar2 *)(as);
6020         }
6021         
6022         memcpy (as, mono_string_chars(s), s->length * 2);
6023         return (gunichar2 *)(as);
6024 }
6025
6026 /**
6027  * mono_string_to_utf32:
6028  * @s: a MonoString
6029  *
6030  * Return an null-terminated array of the UTF-32 (UCS-4) chars
6031  * contained in @s. The result must be freed with g_free().
6032  */
6033 mono_unichar4*
6034 mono_string_to_utf32 (MonoString *s)
6035 {
6036         MONO_REQ_GC_UNSAFE_MODE;
6037
6038         mono_unichar4 *utf32_output = NULL; 
6039         GError *error = NULL;
6040         glong items_written;
6041         
6042         if (s == NULL)
6043                 return NULL;
6044                 
6045         utf32_output = g_utf16_to_ucs4 (s->chars, s->length, NULL, &items_written, &error);
6046         
6047         if (error)
6048                 g_error_free (error);
6049
6050         return utf32_output;
6051 }
6052
6053 /**
6054  * mono_string_from_utf16:
6055  * @data: the UTF16 string (LPWSTR) to convert
6056  *
6057  * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
6058  *
6059  * Returns: a MonoString.
6060  */
6061 MonoString *
6062 mono_string_from_utf16 (gunichar2 *data)
6063 {
6064         MONO_REQ_GC_UNSAFE_MODE;
6065
6066         MonoDomain *domain = mono_domain_get ();
6067         int len = 0;
6068
6069         if (!data)
6070                 return NULL;
6071
6072         while (data [len]) len++;
6073
6074         return mono_string_new_utf16 (domain, data, len);
6075 }
6076
6077 /**
6078  * mono_string_from_utf32:
6079  * @data: the UTF32 string (LPWSTR) to convert
6080  *
6081  * Converts a UTF32 (UCS-4)to a MonoString.
6082  *
6083  * Returns: a MonoString.
6084  */
6085 MonoString *
6086 mono_string_from_utf32 (mono_unichar4 *data)
6087 {
6088         MONO_REQ_GC_UNSAFE_MODE;
6089
6090         MonoString* result = NULL;
6091         mono_unichar2 *utf16_output = NULL;
6092         GError *error = NULL;
6093         glong items_written;
6094         int len = 0;
6095
6096         if (!data)
6097                 return NULL;
6098
6099         while (data [len]) len++;
6100
6101         utf16_output = g_ucs4_to_utf16 (data, len, NULL, &items_written, &error);
6102
6103         if (error)
6104                 g_error_free (error);
6105
6106         result = mono_string_from_utf16 (utf16_output);
6107         g_free (utf16_output);
6108         return result;
6109 }
6110
6111 static char *
6112 mono_string_to_utf8_internal (MonoMemPool *mp, MonoImage *image, MonoString *s, gboolean ignore_error, MonoError *error)
6113 {
6114         MONO_REQ_GC_UNSAFE_MODE;
6115
6116         char *r;
6117         char *mp_s;
6118         int len;
6119
6120         if (ignore_error) {
6121                 r = mono_string_to_utf8_ignore (s);
6122         } else {
6123                 r = mono_string_to_utf8_checked (s, error);
6124                 if (!mono_error_ok (error))
6125                         return NULL;
6126         }
6127
6128         if (!mp && !image)
6129                 return r;
6130
6131         len = strlen (r) + 1;
6132         if (mp)
6133                 mp_s = (char *)mono_mempool_alloc (mp, len);
6134         else
6135                 mp_s = (char *)mono_image_alloc (image, len);
6136
6137         memcpy (mp_s, r, len);
6138
6139         g_free (r);
6140
6141         return mp_s;
6142 }
6143
6144 /**
6145  * mono_string_to_utf8_image:
6146  * @s: a System.String
6147  *
6148  * Same as mono_string_to_utf8, but allocate the string from the image mempool.
6149  */
6150 char *
6151 mono_string_to_utf8_image (MonoImage *image, MonoString *s, MonoError *error)
6152 {
6153         MONO_REQ_GC_UNSAFE_MODE;
6154
6155         return mono_string_to_utf8_internal (NULL, image, s, FALSE, error);
6156 }
6157
6158 /**
6159  * mono_string_to_utf8_mp:
6160  * @s: a System.String
6161  *
6162  * Same as mono_string_to_utf8, but allocate the string from a mempool.
6163  */
6164 char *
6165 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s, MonoError *error)
6166 {
6167         MONO_REQ_GC_UNSAFE_MODE;
6168
6169         return mono_string_to_utf8_internal (mp, NULL, s, FALSE, error);
6170 }
6171
6172
6173 static MonoRuntimeExceptionHandlingCallbacks eh_callbacks;
6174
6175 void
6176 mono_install_eh_callbacks (MonoRuntimeExceptionHandlingCallbacks *cbs)
6177 {
6178         eh_callbacks = *cbs;
6179 }
6180
6181 MonoRuntimeExceptionHandlingCallbacks *
6182 mono_get_eh_callbacks (void)
6183 {
6184         return &eh_callbacks;
6185 }
6186
6187 /**
6188  * mono_raise_exception:
6189  * @ex: exception object
6190  *
6191  * Signal the runtime that the exception @ex has been raised in unmanaged code.
6192  */
6193 void
6194 mono_raise_exception (MonoException *ex) 
6195 {
6196         MONO_REQ_GC_UNSAFE_MODE;
6197
6198         /*
6199          * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
6200          * that will cause gcc to omit the function epilog, causing problems when
6201          * the JIT tries to walk the stack, since the return address on the stack
6202          * will point into the next function in the executable, not this one.
6203          */     
6204         eh_callbacks.mono_raise_exception (ex);
6205 }
6206
6207 void
6208 mono_raise_exception_with_context (MonoException *ex, MonoContext *ctx) 
6209 {
6210         MONO_REQ_GC_UNSAFE_MODE;
6211
6212         eh_callbacks.mono_raise_exception_with_ctx (ex, ctx);
6213 }
6214
6215 /**
6216  * mono_wait_handle_new:
6217  * @domain: Domain where the object will be created
6218  * @handle: Handle for the wait handle
6219  *
6220  * Returns: A new MonoWaitHandle created in the given domain for the given handle
6221  */
6222 MonoWaitHandle *
6223 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
6224 {
6225         MONO_REQ_GC_UNSAFE_MODE;
6226
6227         MonoWaitHandle *res;
6228         gpointer params [1];
6229         static MonoMethod *handle_set;
6230
6231         res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.manualresetevent_class);
6232
6233         /* Even though this method is virtual, it's safe to invoke directly, since the object type matches.  */
6234         if (!handle_set)
6235                 handle_set = mono_class_get_property_from_name (mono_defaults.manualresetevent_class, "Handle")->set;
6236
6237         params [0] = &handle;
6238         mono_runtime_invoke (handle_set, res, params, NULL);
6239
6240         return res;
6241 }
6242
6243 HANDLE
6244 mono_wait_handle_get_handle (MonoWaitHandle *handle)
6245 {
6246         MONO_REQ_GC_UNSAFE_MODE;
6247
6248         static MonoClassField *f_os_handle;
6249         static MonoClassField *f_safe_handle;
6250
6251         if (!f_os_handle && !f_safe_handle) {
6252                 f_os_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "os_handle");
6253                 f_safe_handle = mono_class_get_field_from_name (mono_defaults.manualresetevent_class, "safe_wait_handle");
6254         }
6255
6256         if (f_os_handle) {
6257                 HANDLE retval;
6258                 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
6259                 return retval;
6260         } else {
6261                 MonoSafeHandle *sh;
6262                 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
6263                 return sh->handle;
6264         }
6265 }
6266
6267
6268 static MonoObject*
6269 mono_runtime_capture_context (MonoDomain *domain)
6270 {
6271         MONO_REQ_GC_UNSAFE_MODE;
6272
6273         RuntimeInvokeFunction runtime_invoke;
6274
6275         if (!domain->capture_context_runtime_invoke || !domain->capture_context_method) {
6276                 MonoMethod *method = mono_get_context_capture_method ();
6277                 MonoMethod *wrapper;
6278                 if (!method)
6279                         return NULL;
6280                 wrapper = mono_marshal_get_runtime_invoke (method, FALSE);
6281                 domain->capture_context_runtime_invoke = mono_compile_method (wrapper);
6282                 domain->capture_context_method = mono_compile_method (method);
6283         }
6284
6285         runtime_invoke = (RuntimeInvokeFunction)domain->capture_context_runtime_invoke;
6286
6287         return runtime_invoke (NULL, NULL, NULL, domain->capture_context_method);
6288 }
6289 /**
6290  * mono_async_result_new:
6291  * @domain:domain where the object will be created.
6292  * @handle: wait handle.
6293  * @state: state to pass to AsyncResult
6294  * @data: C closure data.
6295  *
6296  * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
6297  * If the handle is not null, the handle is initialized to a MonOWaitHandle.
6298  *
6299  */
6300 MonoAsyncResult *
6301 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
6302 {
6303         MONO_REQ_GC_UNSAFE_MODE;
6304
6305         MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
6306         MonoObject *context = mono_runtime_capture_context (domain);
6307         /* we must capture the execution context from the original thread */
6308         if (context) {
6309                 MONO_OBJECT_SETREF (res, execution_context, context);
6310                 /* note: result may be null if the flow is suppressed */
6311         }
6312
6313         res->data = (void **)data;
6314         MONO_OBJECT_SETREF (res, object_data, object_data);
6315         MONO_OBJECT_SETREF (res, async_state, state);
6316         if (handle != NULL)
6317                 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
6318
6319         res->sync_completed = FALSE;
6320         res->completed = FALSE;
6321
6322         return res;
6323 }
6324
6325 MonoObject *
6326 ves_icall_System_Runtime_Remoting_Messaging_AsyncResult_Invoke (MonoAsyncResult *ares)
6327 {
6328         MONO_REQ_GC_UNSAFE_MODE;
6329
6330         MonoAsyncCall *ac;
6331         MonoObject *res;
6332
6333         g_assert (ares);
6334         g_assert (ares->async_delegate);
6335
6336         ac = (MonoAsyncCall*) ares->object_data;
6337         if (!ac) {
6338                 res = mono_runtime_delegate_invoke (ares->async_delegate, (void**) &ares->async_state, NULL);
6339         } else {
6340                 gpointer wait_event = NULL;
6341
6342                 ac->msg->exc = NULL;
6343                 res = mono_message_invoke (ares->async_delegate, ac->msg, &ac->msg->exc, &ac->out_args);
6344                 MONO_OBJECT_SETREF (ac, res, res);
6345
6346                 mono_monitor_enter ((MonoObject*) ares);
6347                 ares->completed = 1;
6348                 if (ares->handle)
6349                         wait_event = mono_wait_handle_get_handle ((MonoWaitHandle*) ares->handle);
6350                 mono_monitor_exit ((MonoObject*) ares);
6351
6352                 if (wait_event != NULL)
6353                         SetEvent (wait_event);
6354
6355                 if (ac->cb_method) {
6356                         /* we swallow the excepton as it is the behavior on .NET */
6357                         MonoObject *exc = NULL;
6358                         mono_runtime_invoke (ac->cb_method, ac->cb_target, (gpointer*) &ares, &exc);
6359                         if (exc)
6360                                 mono_unhandled_exception (exc);
6361                 }
6362         }
6363
6364         return res;
6365 }
6366
6367 void
6368 mono_message_init (MonoDomain *domain,
6369                    MonoMethodMessage *this_obj, 
6370                    MonoReflectionMethod *method,
6371                    MonoArray *out_args)
6372 {
6373         MONO_REQ_GC_UNSAFE_MODE;
6374
6375         static MonoClass *object_array_klass;
6376         static MonoClass *byte_array_klass;
6377         static MonoClass *string_array_klass;
6378         MonoError error;
6379         MonoMethodSignature *sig = mono_method_signature (method->method);
6380         MonoString *name;
6381         MonoArray *arr;
6382         int i, j;
6383         char **names;
6384         guint8 arg_type;
6385
6386         if (!object_array_klass) {
6387                 MonoClass *klass;
6388
6389                 klass = mono_array_class_get (mono_defaults.byte_class, 1);
6390                 g_assert (klass);
6391                 byte_array_klass = klass;
6392
6393                 klass = mono_array_class_get (mono_defaults.string_class, 1);
6394                 g_assert (klass);
6395                 string_array_klass = klass;
6396
6397                 klass = mono_array_class_get (mono_defaults.object_class, 1);
6398                 g_assert (klass);
6399
6400                 mono_atomic_store_release (&object_array_klass, klass);
6401         }
6402
6403         MONO_OBJECT_SETREF (this_obj, method, method);
6404
6405         arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), sig->param_count, &error);
6406         mono_error_raise_exception (&error); /* FIXME don't raise here */
6407
6408         MONO_OBJECT_SETREF (this_obj, args, arr);
6409
6410         arr = mono_array_new_specific_checked (mono_class_vtable (domain, byte_array_klass), sig->param_count, &error);
6411         mono_error_raise_exception (&error); /* FIXME don't raise here */
6412
6413         MONO_OBJECT_SETREF (this_obj, arg_types, arr);
6414
6415         this_obj->async_result = NULL;
6416         this_obj->call_type = CallType_Sync;
6417
6418         names = g_new (char *, sig->param_count);
6419         mono_method_get_param_names (method->method, (const char **) names);
6420
6421         arr = mono_array_new_specific_checked (mono_class_vtable (domain, string_array_klass), sig->param_count, &error);
6422         mono_error_raise_exception (&error); /* FIXME don't raise here */
6423
6424         MONO_OBJECT_SETREF (this_obj, names, arr);
6425         
6426         for (i = 0; i < sig->param_count; i++) {
6427                 name = mono_string_new (domain, names [i]);
6428                 mono_array_setref (this_obj->names, i, name);   
6429         }
6430
6431         g_free (names);
6432         for (i = 0, j = 0; i < sig->param_count; i++) {
6433                 if (sig->params [i]->byref) {
6434                         if (out_args) {
6435                                 MonoObject* arg = (MonoObject *)mono_array_get (out_args, gpointer, j);
6436                                 mono_array_setref (this_obj->args, i, arg);
6437                                 j++;
6438                         }
6439                         arg_type = 2;
6440                         if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
6441                                 arg_type |= 1;
6442                 } else {
6443                         arg_type = 1;
6444                         if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
6445                                 arg_type |= 4;
6446                 }
6447                 mono_array_set (this_obj->arg_types, guint8, i, arg_type);
6448         }
6449 }
6450
6451 #ifndef DISABLE_REMOTING
6452 /**
6453  * mono_remoting_invoke:
6454  * @real_proxy: pointer to a RealProxy object
6455  * @msg: The MonoMethodMessage to execute
6456  * @exc: used to store exceptions
6457  * @out_args: used to store output arguments
6458  *
6459  * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
6460  * IMessage interface and it is not trivial to extract results from there. So
6461  * we call an helper method PrivateInvoke instead of calling
6462  * RealProxy::Invoke() directly.
6463  *
6464  * Returns: the result object.
6465  */
6466 MonoObject *
6467 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, 
6468                       MonoObject **exc, MonoArray **out_args)
6469 {
6470         MONO_REQ_GC_UNSAFE_MODE;
6471
6472         MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
6473         gpointer pa [4];
6474
6475         /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
6476
6477         if (!im) {
6478                 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
6479                 if (!im)
6480                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6481                 real_proxy->vtable->domain->private_invoke_method = im;
6482         }
6483
6484         pa [0] = real_proxy;
6485         pa [1] = msg;
6486         pa [2] = exc;
6487         pa [3] = out_args;
6488
6489         return mono_runtime_invoke (im, NULL, pa, exc);
6490 }
6491 #endif
6492
6493 MonoObject *
6494 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
6495                      MonoObject **exc, MonoArray **out_args) 
6496 {
6497         MONO_REQ_GC_UNSAFE_MODE;
6498
6499         static MonoClass *object_array_klass;
6500         MonoError error;
6501         MonoDomain *domain; 
6502         MonoMethod *method;
6503         MonoMethodSignature *sig;
6504         MonoObject *ret;
6505         MonoArray *arr;
6506         int i, j, outarg_count = 0;
6507
6508 #ifndef DISABLE_REMOTING
6509         if (target && mono_object_is_transparent_proxy (target)) {
6510                 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
6511                 if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6512                         target = tp->rp->unwrapped_server;
6513                 } else {
6514                         return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
6515                 }
6516         }
6517 #endif
6518
6519         domain = mono_domain_get (); 
6520         method = msg->method->method;
6521         sig = mono_method_signature (method);
6522
6523         for (i = 0; i < sig->param_count; i++) {
6524                 if (sig->params [i]->byref) 
6525                         outarg_count++;
6526         }
6527
6528         if (!object_array_klass) {
6529                 MonoClass *klass;
6530
6531                 klass = mono_array_class_get (mono_defaults.object_class, 1);
6532                 g_assert (klass);
6533
6534                 mono_memory_barrier ();
6535                 object_array_klass = klass;
6536         }
6537
6538         arr = mono_array_new_specific_checked (mono_class_vtable (domain, object_array_klass), outarg_count, &error);
6539         mono_error_raise_exception (&error); /* FIXME don't raise here */
6540
6541         mono_gc_wbarrier_generic_store (out_args, (MonoObject*) arr);
6542         *exc = NULL;
6543
6544         ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
6545
6546         for (i = 0, j = 0; i < sig->param_count; i++) {
6547                 if (sig->params [i]->byref) {
6548                         MonoObject* arg;
6549                         arg = (MonoObject *)mono_array_get (msg->args, gpointer, i);
6550                         mono_array_setref (*out_args, j, arg);
6551                         j++;
6552                 }
6553         }
6554
6555         return ret;
6556 }
6557
6558 /**
6559  * mono_object_to_string:
6560  * @obj: The object
6561  * @exc: Any exception thrown by ToString (). May be NULL.
6562  *
6563  * Returns: the result of calling ToString () on an object.
6564  */
6565 MonoString *
6566 mono_object_to_string (MonoObject *obj, MonoObject **exc)
6567 {
6568         MONO_REQ_GC_UNSAFE_MODE;
6569
6570         static MonoMethod *to_string = NULL;
6571         MonoMethod *method;
6572         void *target = obj;
6573
6574         g_assert (obj);
6575
6576         if (!to_string)
6577                 to_string = mono_class_get_method_from_name_flags (mono_get_object_class (), "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
6578
6579         method = mono_object_get_virtual_method (obj, to_string);
6580
6581         // Unbox value type if needed
6582         if (mono_class_is_valuetype (mono_method_get_class (method))) {
6583                 target = mono_object_unbox (obj);
6584         }
6585
6586         return (MonoString *) mono_runtime_invoke (method, target, NULL, exc);
6587 }
6588
6589 /**
6590  * mono_print_unhandled_exception:
6591  * @exc: The exception
6592  *
6593  * Prints the unhandled exception.
6594  */
6595 void
6596 mono_print_unhandled_exception (MonoObject *exc)
6597 {
6598         MONO_REQ_GC_UNSAFE_MODE;
6599
6600         MonoString * str;
6601         char *message = (char*)"";
6602         gboolean free_message = FALSE;
6603         MonoError error;
6604
6605         if (exc == (MonoObject*)mono_object_domain (exc)->out_of_memory_ex) {
6606                 message = g_strdup ("OutOfMemoryException");
6607                 free_message = TRUE;
6608         } else if (exc == (MonoObject*)mono_object_domain (exc)->stack_overflow_ex) {
6609                 message = g_strdup ("StackOverflowException"); //if we OVF, we can't expect to have stack space to JIT Exception::ToString.
6610                 free_message = TRUE;
6611         } else {
6612                 
6613                 if (((MonoException*)exc)->native_trace_ips) {
6614                         message = mono_exception_get_native_backtrace ((MonoException*)exc);
6615                         free_message = TRUE;
6616                 } else {
6617                         MonoObject *other_exc = NULL;
6618                         str = mono_object_to_string (exc, &other_exc);
6619                         if (other_exc) {
6620                                 char *original_backtrace = mono_exception_get_managed_backtrace ((MonoException*)exc);
6621                                 char *nested_backtrace = mono_exception_get_managed_backtrace ((MonoException*)other_exc);
6622                                 
6623                                 message = g_strdup_printf ("Nested exception detected.\nOriginal Exception: %s\nNested exception:%s\n",
6624                                         original_backtrace, nested_backtrace);
6625
6626                                 g_free (original_backtrace);
6627                                 g_free (nested_backtrace);
6628                                 free_message = TRUE;
6629                         } else if (str) {
6630                                 message = mono_string_to_utf8_checked (str, &error);
6631                                 if (!mono_error_ok (&error)) {
6632                                         mono_error_cleanup (&error);
6633                                         message = (char *) "";
6634                                 } else {
6635                                         free_message = TRUE;
6636                                 }
6637                         }
6638                 }
6639         }
6640
6641         /*
6642          * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space, 
6643          *         exc->vtable->klass->name, message);
6644          */
6645         g_printerr ("\nUnhandled Exception:\n%s\n", message);
6646         
6647         if (free_message)
6648                 g_free (message);
6649 }
6650
6651 /**
6652  * mono_delegate_ctor:
6653  * @this: pointer to an uninitialized delegate object
6654  * @target: target object
6655  * @addr: pointer to native code
6656  * @method: method
6657  *
6658  * Initialize a delegate and sets a specific method, not the one
6659  * associated with addr.  This is useful when sharing generic code.
6660  * In that case addr will most probably not be associated with the
6661  * correct instantiation of the method.
6662  */
6663 void
6664 mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpointer addr, MonoMethod *method)
6665 {
6666         MONO_REQ_GC_UNSAFE_MODE;
6667
6668         MonoDelegate *delegate = (MonoDelegate *)this_obj;
6669
6670         g_assert (this_obj);
6671         g_assert (addr);
6672
6673         g_assert (mono_class_has_parent (mono_object_class (this_obj), mono_defaults.multicastdelegate_class));
6674
6675         if (method)
6676                 delegate->method = method;
6677
6678         mono_stats.delegate_creations++;
6679
6680 #ifndef DISABLE_REMOTING
6681         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
6682                 g_assert (method);
6683                 method = mono_marshal_get_remoting_invoke (method);
6684                 delegate->method_ptr = mono_compile_method (method);
6685                 MONO_OBJECT_SETREF (delegate, target, target);
6686         } else
6687 #endif
6688         {
6689                 delegate->method_ptr = addr;
6690                 MONO_OBJECT_SETREF (delegate, target, target);
6691         }
6692
6693         delegate->invoke_impl = arch_create_delegate_trampoline (delegate->object.vtable->domain, delegate->object.vtable->klass);
6694         if (callbacks.init_delegate)
6695                 callbacks.init_delegate (delegate);
6696 }
6697
6698 /**
6699  * mono_delegate_ctor:
6700  * @this: pointer to an uninitialized delegate object
6701  * @target: target object
6702  * @addr: pointer to native code
6703  *
6704  * This is used to initialize a delegate.
6705  */
6706 void
6707 mono_delegate_ctor (MonoObject *this_obj, MonoObject *target, gpointer addr)
6708 {
6709         MONO_REQ_GC_UNSAFE_MODE;
6710
6711         MonoDomain *domain = mono_domain_get ();
6712         MonoJitInfo *ji;
6713         MonoMethod *method = NULL;
6714
6715         g_assert (addr);
6716
6717         ji = mono_jit_info_table_find (domain, (char *)mono_get_addr_from_ftnptr (addr));
6718         /* Shared code */
6719         if (!ji && domain != mono_get_root_domain ())
6720                 ji = mono_jit_info_table_find (mono_get_root_domain (), (char *)mono_get_addr_from_ftnptr (addr));
6721         if (ji) {
6722                 method = mono_jit_info_get_method (ji);
6723                 g_assert (!method->klass->generic_container);
6724         }
6725
6726         mono_delegate_ctor_with_method (this_obj, target, addr, method);
6727 }
6728
6729 /**
6730  * mono_method_call_message_new:
6731  * @method: method to encapsulate
6732  * @params: parameters to the method
6733  * @invoke: optional, delegate invoke.
6734  * @cb: async callback delegate.
6735  * @state: state passed to the async callback.
6736  *
6737  * Translates arguments pointers into a MonoMethodMessage.
6738  */
6739 MonoMethodMessage *
6740 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke, 
6741                               MonoDelegate **cb, MonoObject **state)
6742 {
6743         MONO_REQ_GC_UNSAFE_MODE;
6744
6745         MonoDomain *domain = mono_domain_get ();
6746         MonoMethodSignature *sig = mono_method_signature (method);
6747         MonoMethodMessage *msg;
6748         int i, count;
6749
6750         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class); 
6751         
6752         if (invoke) {
6753                 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
6754                 count =  sig->param_count - 2;
6755         } else {
6756                 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
6757                 count =  sig->param_count;
6758         }
6759
6760         for (i = 0; i < count; i++) {
6761                 gpointer vpos;
6762                 MonoClass *klass;
6763                 MonoObject *arg;
6764
6765                 if (sig->params [i]->byref)
6766                         vpos = *((gpointer *)params [i]);
6767                 else 
6768                         vpos = params [i];
6769
6770                 klass = mono_class_from_mono_type (sig->params [i]);
6771
6772                 if (klass->valuetype)
6773                         arg = mono_value_box (domain, klass, vpos);
6774                 else 
6775                         arg = *((MonoObject **)vpos);
6776                       
6777                 mono_array_setref (msg->args, i, arg);
6778         }
6779
6780         if (cb != NULL && state != NULL) {
6781                 *cb = *((MonoDelegate **)params [i]);
6782                 i++;
6783                 *state = *((MonoObject **)params [i]);
6784         }
6785
6786         return msg;
6787 }
6788
6789 /**
6790  * mono_method_return_message_restore:
6791  *
6792  * Restore results from message based processing back to arguments pointers
6793  */
6794 void
6795 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
6796 {
6797         MONO_REQ_GC_UNSAFE_MODE;
6798
6799         MonoMethodSignature *sig = mono_method_signature (method);
6800         int i, j, type, size, out_len;
6801         
6802         if (out_args == NULL)
6803                 return;
6804         out_len = mono_array_length (out_args);
6805         if (out_len == 0)
6806                 return;
6807
6808         for (i = 0, j = 0; i < sig->param_count; i++) {
6809                 MonoType *pt = sig->params [i];
6810
6811                 if (pt->byref) {
6812                         char *arg;
6813                         if (j >= out_len)
6814                                 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
6815
6816                         arg = (char *)mono_array_get (out_args, gpointer, j);
6817                         type = pt->type;
6818
6819                         g_assert (type != MONO_TYPE_VOID);
6820
6821                         if (MONO_TYPE_IS_REFERENCE (pt)) {
6822                                 mono_gc_wbarrier_generic_store (*((MonoObject ***)params [i]), (MonoObject *)arg);
6823                         } else {
6824                                 if (arg) {
6825                                         MonoClass *klass = ((MonoObject*)arg)->vtable->klass;
6826                                         size = mono_class_value_size (klass, NULL);
6827                                         if (klass->has_references)
6828                                                 mono_gc_wbarrier_value_copy (*((gpointer *)params [i]), arg + sizeof (MonoObject), 1, klass);
6829                                         else
6830                                                 mono_gc_memmove_atomic (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
6831                                 } else {
6832                                         size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
6833                                         mono_gc_bzero_atomic (*((gpointer *)params [i]), size);
6834                                 }
6835                         }
6836
6837                         j++;
6838                 }
6839         }
6840 }
6841
6842 #ifndef DISABLE_REMOTING
6843
6844 /**
6845  * mono_load_remote_field:
6846  * @this: pointer to an object
6847  * @klass: klass of the object containing @field
6848  * @field: the field to load
6849  * @res: a storage to store the result
6850  *
6851  * This method is called by the runtime on attempts to load fields of
6852  * transparent proxy objects. @this points to such TP, @klass is the class of
6853  * the object containing @field. @res is a storage location which can be
6854  * used to store the result.
6855  *
6856  * Returns: an address pointing to the value of field.
6857  */
6858 gpointer
6859 mono_load_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer *res)
6860 {
6861         MONO_REQ_GC_UNSAFE_MODE;
6862
6863         static MonoMethod *getter = NULL;
6864         MonoDomain *domain = mono_domain_get ();
6865         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6866         MonoClass *field_class;
6867         MonoMethodMessage *msg;
6868         MonoArray *out_args;
6869         MonoObject *exc;
6870         char* full_name;
6871
6872         g_assert (mono_object_is_transparent_proxy (this_obj));
6873         g_assert (res != NULL);
6874
6875         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6876                 mono_field_get_value (tp->rp->unwrapped_server, field, res);
6877                 return res;
6878         }
6879         
6880         if (!getter) {
6881                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6882                 if (!getter)
6883                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6884         }
6885         
6886         field_class = mono_class_from_mono_type (field->type);
6887
6888         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6889         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6890         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6891
6892         full_name = mono_type_get_full_name (klass);
6893         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6894         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6895         g_free (full_name);
6896
6897         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6898
6899         if (exc) mono_raise_exception ((MonoException *)exc);
6900
6901         if (mono_array_length (out_args) == 0)
6902                 return NULL;
6903
6904         *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
6905
6906         if (field_class->valuetype) {
6907                 return ((char *)*res) + sizeof (MonoObject);
6908         } else
6909                 return res;
6910 }
6911
6912 /**
6913  * mono_load_remote_field_new:
6914  * @this: 
6915  * @klass: 
6916  * @field:
6917  *
6918  * Missing documentation.
6919  */
6920 MonoObject *
6921 mono_load_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field)
6922 {
6923         MONO_REQ_GC_UNSAFE_MODE;
6924
6925         static MonoMethod *getter = NULL;
6926         MonoDomain *domain = mono_domain_get ();
6927         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6928         MonoClass *field_class;
6929         MonoMethodMessage *msg;
6930         MonoArray *out_args;
6931         MonoObject *exc, *res;
6932         char* full_name;
6933
6934         g_assert (mono_object_is_transparent_proxy (this_obj));
6935
6936         field_class = mono_class_from_mono_type (field->type);
6937
6938         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
6939                 gpointer val;
6940                 if (field_class->valuetype) {
6941                         res = mono_object_new (domain, field_class);
6942                         val = ((gchar *) res) + sizeof (MonoObject);
6943                 } else {
6944                         val = &res;
6945                 }
6946                 mono_field_get_value (tp->rp->unwrapped_server, field, val);
6947                 return res;
6948         }
6949
6950         if (!getter) {
6951                 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
6952                 if (!getter)
6953                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
6954         }
6955         
6956         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
6957         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
6958
6959         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
6960
6961         full_name = mono_type_get_full_name (klass);
6962         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
6963         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
6964         g_free (full_name);
6965
6966         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
6967
6968         if (exc) mono_raise_exception ((MonoException *)exc);
6969
6970         if (mono_array_length (out_args) == 0)
6971                 res = NULL;
6972         else
6973                 res = mono_array_get (out_args, MonoObject *, 0);
6974
6975         return res;
6976 }
6977
6978 /**
6979  * mono_store_remote_field:
6980  * @this_obj: pointer to an object
6981  * @klass: klass of the object containing @field
6982  * @field: the field to load
6983  * @val: the value/object to store
6984  *
6985  * This method is called by the runtime on attempts to store fields of
6986  * transparent proxy objects. @this_obj points to such TP, @klass is the class of
6987  * the object containing @field. @val is the new value to store in @field.
6988  */
6989 void
6990 mono_store_remote_field (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, gpointer val)
6991 {
6992         MONO_REQ_GC_UNSAFE_MODE;
6993
6994         static MonoMethod *setter = NULL;
6995         MonoDomain *domain = mono_domain_get ();
6996         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
6997         MonoClass *field_class;
6998         MonoMethodMessage *msg;
6999         MonoArray *out_args;
7000         MonoObject *exc;
7001         MonoObject *arg;
7002         char* full_name;
7003
7004         g_assert (mono_object_is_transparent_proxy (this_obj));
7005
7006         field_class = mono_class_from_mono_type (field->type);
7007
7008         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7009                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
7010                 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
7011                 return;
7012         }
7013
7014         if (!setter) {
7015                 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7016                 if (!setter)
7017                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7018         }
7019
7020         if (field_class->valuetype)
7021                 arg = mono_value_box (domain, field_class, val);
7022         else 
7023                 arg = *((MonoObject **)val);
7024                 
7025
7026         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
7027         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
7028
7029         full_name = mono_type_get_full_name (klass);
7030         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7031         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7032         mono_array_setref (msg->args, 2, arg);
7033         g_free (full_name);
7034
7035         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7036
7037         if (exc) mono_raise_exception ((MonoException *)exc);
7038 }
7039
7040 /**
7041  * mono_store_remote_field_new:
7042  * @this_obj:
7043  * @klass:
7044  * @field:
7045  * @arg:
7046  *
7047  * Missing documentation
7048  */
7049 void
7050 mono_store_remote_field_new (MonoObject *this_obj, MonoClass *klass, MonoClassField *field, MonoObject *arg)
7051 {
7052         MONO_REQ_GC_UNSAFE_MODE;
7053
7054         static MonoMethod *setter = NULL;
7055         MonoDomain *domain = mono_domain_get ();
7056         MonoTransparentProxy *tp = (MonoTransparentProxy *) this_obj;
7057         MonoClass *field_class;
7058         MonoMethodMessage *msg;
7059         MonoArray *out_args;
7060         MonoObject *exc;
7061         char* full_name;
7062
7063         g_assert (mono_object_is_transparent_proxy (this_obj));
7064
7065         field_class = mono_class_from_mono_type (field->type);
7066
7067         if (mono_class_is_contextbound (tp->remote_class->proxy_class) && tp->rp->context == (MonoObject *) mono_context_get ()) {
7068                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
7069                 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
7070                 return;
7071         }
7072
7073         if (!setter) {
7074                 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
7075                 if (!setter)
7076                         mono_raise_exception (mono_get_exception_not_supported ("Linked away."));
7077         }
7078
7079         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
7080         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
7081
7082         full_name = mono_type_get_full_name (klass);
7083         mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
7084         mono_array_setref (msg->args, 1, mono_string_new (domain, mono_field_get_name (field)));
7085         mono_array_setref (msg->args, 2, arg);
7086         g_free (full_name);
7087
7088         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
7089
7090         if (exc) mono_raise_exception ((MonoException *)exc);
7091 }
7092 #endif
7093
7094 /*
7095  * mono_create_ftnptr:
7096  *
7097  *   Given a function address, create a function descriptor for it.
7098  * This is only needed on some platforms.
7099  */
7100 gpointer
7101 mono_create_ftnptr (MonoDomain *domain, gpointer addr)
7102 {
7103         return callbacks.create_ftnptr (domain, addr);
7104 }
7105
7106 /*
7107  * mono_get_addr_from_ftnptr:
7108  *
7109  *   Given a pointer to a function descriptor, return the function address.
7110  * This is only needed on some platforms.
7111  */
7112 gpointer
7113 mono_get_addr_from_ftnptr (gpointer descr)
7114 {
7115         return callbacks.get_addr_from_ftnptr (descr);
7116 }       
7117
7118 /**
7119  * mono_string_chars:
7120  * @s: a MonoString
7121  *
7122  * Returns a pointer to the UCS16 characters stored in the MonoString
7123  */
7124 gunichar2 *
7125 mono_string_chars (MonoString *s)
7126 {
7127         // MONO_REQ_GC_UNSAFE_MODE; //FIXME too much trouble for now
7128
7129         return s->chars;
7130 }
7131
7132 /**
7133  * mono_string_length:
7134  * @s: MonoString
7135  *
7136  * Returns the lenght in characters of the string
7137  */
7138 int
7139 mono_string_length (MonoString *s)
7140 {
7141         MONO_REQ_GC_UNSAFE_MODE;
7142
7143         return s->length;
7144 }
7145
7146 /**
7147  * mono_array_length:
7148  * @array: a MonoArray*
7149  *
7150  * Returns the total number of elements in the array. This works for
7151  * both vectors and multidimensional arrays.
7152  */
7153 uintptr_t
7154 mono_array_length (MonoArray *array)
7155 {
7156         MONO_REQ_GC_UNSAFE_MODE;
7157
7158         return array->max_length;
7159 }
7160
7161 /**
7162  * mono_array_addr_with_size:
7163  * @array: a MonoArray*
7164  * @size: size of the array elements
7165  * @idx: index into the array
7166  *
7167  * Returns the address of the @idx element in the array.
7168  */
7169 char*
7170 mono_array_addr_with_size (MonoArray *array, int size, uintptr_t idx)
7171 {
7172         MONO_REQ_GC_UNSAFE_MODE;
7173
7174         return ((char*)(array)->vector) + size * idx;
7175 }
7176
7177
7178 MonoArray *
7179 mono_glist_to_array (GList *list, MonoClass *eclass) 
7180 {
7181         MonoDomain *domain = mono_domain_get ();
7182         MonoArray *res;
7183         int len, i;
7184
7185         if (!list)
7186                 return NULL;
7187
7188         len = g_list_length (list);
7189         res = mono_array_new (domain, eclass, len);
7190
7191         for (i = 0; list; list = list->next, i++)
7192                 mono_array_set (res, gpointer, i, list->data);
7193
7194         return res;
7195 }
7196