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