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