In metadata:
[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  * (C) 2001-2004 Ximian, Inc.
9  */
10 #include <config.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <signal.h>
14 #include <string.h>
15 #include <mono/metadata/mono-endian.h>
16 #include <mono/metadata/tabledefs.h>
17 #include <mono/metadata/tokentype.h>
18 #include <mono/metadata/loader.h>
19 #include <mono/metadata/object.h>
20 #include <mono/metadata/gc-internal.h>
21 #include <mono/metadata/exception.h>
22 #include <mono/metadata/domain-internals.h>
23 #include "mono/metadata/metadata-internals.h"
24 #include "mono/metadata/class-internals.h"
25 #include <mono/metadata/assembly.h>
26 #include <mono/metadata/threadpool.h>
27 #include <mono/metadata/marshal.h>
28 #include "mono/metadata/debug-helpers.h"
29 #include "mono/metadata/marshal.h"
30 #include <mono/metadata/threads.h>
31 #include <mono/metadata/threads-types.h>
32 #include <mono/metadata/environment.h>
33 #include "mono/metadata/profiler-private.h"
34 #include <mono/os/gc_wrapper.h>
35 #include <mono/utils/strenc.h>
36
37 /*
38  * Enable typed allocation using the GC_gcj_malloc function.
39  */
40 #ifdef HAVE_GC_GCJ_MALLOC
41 #define CREATION_SPEEDUP 1
42 #endif
43
44 static void
45 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
46
47 static MonoString*
48 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig);
49
50 void
51 mono_runtime_object_init (MonoObject *this)
52 {
53         int i;
54         MonoMethod *method = NULL;
55         MonoClass *klass = this->vtable->klass;
56
57         for (i = 0; i < klass->method.count; ++i) {
58                 if (!strcmp (".ctor", klass->methods [i]->name) &&
59                     klass->methods [i]->signature->param_count == 0) {
60                         method = klass->methods [i];
61                         break;
62                 }
63         }
64
65         g_assert (method);
66
67         if (method->klass->valuetype)
68                 this = mono_object_unbox (this);
69         mono_runtime_invoke (method, this, NULL, NULL);
70 }
71
72 /* The pseudo algorithm for type initialization from the spec
73 Note it doesn't say anything about domains - only threads.
74
75 2. If the type is initialized you are done.
76 2.1. If the type is not yet initialized, try to take an 
77      initialization lock.  
78 2.2. If successful, record this thread as responsible for 
79      initializing the type and proceed to step 2.3.
80 2.2.1. If not, see whether this thread or any thread 
81      waiting for this thread to complete already holds the lock.
82 2.2.2. If so, return since blocking would create a deadlock.  This thread 
83      will now see an incompletely initialized state for the type, 
84      but no deadlock will arise.
85 2.2.3  If not, block until the type is initialized then return.
86 2.3 Initialize the parent type and then all interfaces implemented 
87     by this type.
88 2.4 Execute the type initialization code for this type.
89 2.5 Mark the type as initialized, release the initialization lock, 
90     awaken any threads waiting for this type to be initialized, 
91     and return.
92
93 */
94
95 typedef struct
96 {
97         guint32 initializing_tid;
98         guint32 waiting_count;
99         gboolean done;
100         CRITICAL_SECTION initialization_section;
101 } TypeInitializationLock;
102
103 /* for locking access to type_initialization_hash and blocked_thread_hash */
104 static CRITICAL_SECTION type_initialization_section;
105
106 /* from vtable to lock */
107 static GHashTable *type_initialization_hash;
108
109 /* from thread id to thread id being waited on */
110 static GHashTable *blocked_thread_hash;
111
112 /* Main thread */
113 static MonoThread *main_thread;
114
115 void
116 mono_type_initialization_init (void)
117 {
118         InitializeCriticalSection (&type_initialization_section);
119         type_initialization_hash = g_hash_table_new (NULL, NULL);
120         blocked_thread_hash = g_hash_table_new (NULL, NULL);
121 }
122
123 /*
124  * mono_runtime_class_init:
125  * @vtable: vtable that needs to be initialized
126  *
127  * This routine calls the class constructor for @vtable.
128  */
129 void
130 mono_runtime_class_init (MonoVTable *vtable)
131 {
132         int i;
133         MonoException *exc;
134         MonoException *exc_to_throw;
135         MonoMethod *method = NULL;
136         MonoClass *klass;
137         gchar *full_name;
138         gboolean found;
139
140         MONO_ARCH_SAVE_REGS;
141
142         if (vtable->initialized)
143                 return;
144
145         exc = NULL;
146         found = FALSE;
147         klass = vtable->klass;
148
149         for (i = 0; i < klass->method.count; ++i) {
150                 method = klass->methods [i];
151                 if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && 
152                     (strcmp (".cctor", method->name) == 0)) {
153                         found = TRUE;
154                         break;
155                 }
156         }
157
158         if (found) {
159                 MonoDomain *domain = vtable->domain;
160                 TypeInitializationLock *lock;
161                 guint32 tid = GetCurrentThreadId();
162                 int do_initialization = 0;
163                 MonoDomain *last_domain = NULL;
164
165                 EnterCriticalSection (&type_initialization_section);
166                 /* double check... */
167                 if (vtable->initialized) {
168                         LeaveCriticalSection (&type_initialization_section);
169                         return;
170                 }
171                 lock = g_hash_table_lookup (type_initialization_hash, vtable);
172                 if (lock == NULL) {
173                         /* This thread will get to do the initialization */
174                         if (mono_domain_get () != domain) {
175                                 /* Transfer into the target domain */
176                                 last_domain = mono_domain_get ();
177                                 if (!mono_domain_set (domain, FALSE)) {
178                                         vtable->initialized = 1;
179                                         LeaveCriticalSection (&type_initialization_section);
180                                         mono_raise_exception (mono_get_exception_appdomain_unloaded ());
181                                 }
182                         }
183                         lock = g_malloc (sizeof(TypeInitializationLock));
184                         InitializeCriticalSection (&lock->initialization_section);
185                         lock->initializing_tid = tid;
186                         lock->waiting_count = 1;
187                         lock->done = FALSE;
188                         /* grab the vtable lock while this thread still owns type_initialization_section */
189                         EnterCriticalSection (&lock->initialization_section);
190                         g_hash_table_insert (type_initialization_hash, vtable, lock);
191                         do_initialization = 1;
192                 } else {
193                         gpointer blocked;
194                         TypeInitializationLock *pending_lock;
195
196                         if (lock->initializing_tid == tid || lock->done) {
197                                 LeaveCriticalSection (&type_initialization_section);
198                                 return;
199                         }
200                         /* see if the thread doing the initialization is already blocked on this thread */
201                         blocked = GUINT_TO_POINTER (lock->initializing_tid);
202                         while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
203                                 if (pending_lock->initializing_tid == tid) {
204                                         if (!pending_lock->done) {
205                                                 LeaveCriticalSection (&type_initialization_section);
206                                                 return;
207                                         } else {
208                                                 /* the thread doing the initialization is blocked on this thread,
209                                                    but on a lock that has already been freed. It just hasn't got
210                                                    time to awake */
211                                                 break;
212                                         }
213                                 }
214                                 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
215                         }
216                         ++lock->waiting_count;
217                         /* record the fact that we are waiting on the initializing thread */
218                         g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
219                 }
220                 LeaveCriticalSection (&type_initialization_section);
221
222                 if (do_initialization) {
223                         mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
224                         if (last_domain)
225                                 mono_domain_set (last_domain, TRUE);
226                         lock->done = TRUE;
227                         LeaveCriticalSection (&lock->initialization_section);
228                 } else {
229                         /* this just blocks until the initializing thread is done */
230                         EnterCriticalSection (&lock->initialization_section);
231                         LeaveCriticalSection (&lock->initialization_section);
232                 }
233
234                 EnterCriticalSection (&type_initialization_section);
235                 if (lock->initializing_tid != tid)
236                         g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
237                 --lock->waiting_count;
238                 if (lock->waiting_count == 0) {
239                         DeleteCriticalSection (&lock->initialization_section);
240                         g_hash_table_remove (type_initialization_hash, vtable);
241                         g_free (lock);
242                 }
243                 vtable->initialized = 1;
244                 /* FIXME: if the cctor fails, the type must be marked as unusable */
245                 LeaveCriticalSection (&type_initialization_section);
246         } else {
247                 vtable->initialized = 1;
248                 return;
249         }
250
251         if (exc == NULL ||
252             (klass->image == mono_defaults.corlib &&            
253              !strcmp (klass->name_space, "System") &&
254              !strcmp (klass->name, "TypeInitializationException")))
255                 return; /* No static constructor found or avoid infinite loop */
256
257         if (klass->name_space && *klass->name_space)
258                 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
259         else
260                 full_name = g_strdup (klass->name);
261
262         exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
263         g_free (full_name);
264
265         mono_raise_exception (exc_to_throw);
266 }
267
268 static
269 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
270 {
271         TypeInitializationLock *lock = (TypeInitializationLock*) value;
272         if (lock->initializing_tid == GPOINTER_TO_UINT (user)) {
273                 lock->done = TRUE;
274                 LeaveCriticalSection (&lock->initialization_section);
275                 --lock->waiting_count;
276                 if (lock->waiting_count == 0) {
277                         DeleteCriticalSection (&lock->initialization_section);
278                         g_free (lock);
279                         return TRUE;
280                 }
281         }
282         return FALSE;
283 }
284
285 void
286 mono_release_type_locks (MonoThread *thread)
287 {
288         EnterCriticalSection (&type_initialization_section);
289         g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, GUINT_TO_POINTER (thread->tid));
290         LeaveCriticalSection (&type_initialization_section);
291 }
292
293 static gpointer
294 default_trampoline (MonoMethod *method)
295 {
296         return method;
297 }
298
299 static gpointer
300 default_remoting_trampoline (MonoMethod *method, MonoRemotingTarget target)
301 {
302         g_error ("remoting not installed");
303         return NULL;
304 }
305
306 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
307 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
308
309 void
310 mono_install_trampoline (MonoTrampoline func) 
311 {
312         arch_create_jit_trampoline = func? func: default_trampoline;
313 }
314
315 void
316 mono_install_remoting_trampoline (MonoRemotingTrampoline func) 
317 {
318         arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
319 }
320
321 static MonoCompileFunc default_mono_compile_method = NULL;
322
323 /**
324  * mono_install_compile_method:
325  * @func: function to install
326  *
327  * This is a VM internal routine
328  */
329 void        
330 mono_install_compile_method (MonoCompileFunc func)
331 {
332         default_mono_compile_method = func;
333 }
334
335 /**
336  * mono_compile_method:
337  * @method: The method to compile.
338  *
339  * This JIT-compiles the method, and returns the pointer to the native code
340  * produced.
341  */
342 gpointer 
343 mono_compile_method (MonoMethod *method)
344 {
345         if (!default_mono_compile_method) {
346                 g_error ("compile method called on uninitialized runtime");
347                 return NULL;
348         }
349         return default_mono_compile_method (method);
350 }
351
352 static MonoFreeMethodFunc default_mono_free_method = NULL;
353
354 /**
355  * mono_install_free_method:
356  * @func: pointer to the MonoFreeMethodFunc used to release a method
357  *
358  * This is an internal VM routine, it is used for the engines to
359  * register a handler to release the resources associated with a method.
360  *
361  * Methods are freed when no more references to the delegate that holds
362  * them are left.
363  */
364 void
365 mono_install_free_method (MonoFreeMethodFunc func)
366 {
367         default_mono_free_method = func;
368 }
369
370 /**
371  * mono_runtime_free_method:
372  * @domain; domain where the method is hosted
373  * @method: method to release
374  *
375  * This routine is invoked to free the resources associated with
376  * a method that has been JIT compiled.  This is used to discard
377  * methods that were used only temporarily (for example, used in marshalling)
378  *
379  */
380 void
381 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
382 {
383         if (default_mono_free_method != NULL)
384                 default_mono_free_method (domain, method);
385
386         /* 
387          * FIXME: This causes crashes because the types inside signatures and
388          * locals are shared.
389          */
390         /* mono_free_method (method); */
391 }
392
393 #if 0 && HAVE_BOEHM_GC
394 static void
395 vtable_finalizer (void *obj, void *data) {
396         g_print ("%s finalized (%p)\n", (char*)data, obj);
397 }
398 #endif
399
400 #if CREATION_SPEEDUP
401
402 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
403
404 /*
405  * The vtables in the root appdomain are assumed to be reachable by other 
406  * roots, and we don't use typed allocation in the other domains.
407  */
408
409 #define GC_HEADER_BITMAP (1 << (G_STRUCT_OFFSET (MonoObject,synchronisation) / sizeof(gpointer)))
410
411 static void
412 mono_class_compute_gc_descriptor (MonoClass *class)
413 {
414         MonoClassField *field;
415         guint64 bitmap;
416         guint32 bm [2];
417         int i;
418         static gboolean gcj_inited = FALSE;
419
420         if (!gcj_inited) {
421                 gcj_inited = TRUE;
422
423                 GC_init_gcj_malloc (5, NULL);
424
425                 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
426
427 #ifdef GC_REDIRECT_TO_LOCAL
428                 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
429                 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
430 #endif
431                 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
432                 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
433         }
434
435         if (!class->inited)
436                 mono_class_init (class);
437
438         if (class->gc_descr_inited)
439                 return;
440
441         class->gc_descr_inited = TRUE;
442         class->gc_descr = GC_NO_DESCRIPTOR;
443
444         if (class == mono_defaults.string_class) {
445                 bitmap = GC_HEADER_BITMAP;
446                 class->gc_descr = (gpointer)GC_make_descriptor ((GC_bitmap)&bitmap, 2);
447         }
448         else if (class->rank) {
449                 mono_class_compute_gc_descriptor (class->element_class);
450
451                 if (class->element_class->valuetype && (class->element_class->gc_descr != GC_NO_DESCRIPTOR) && (class->element_class->gc_bitmap == GC_HEADER_BITMAP)) {
452                         bitmap = GC_HEADER_BITMAP;
453                         if (class->rank > 1)
454                                 bitmap += 1 << (G_STRUCT_OFFSET (MonoArray,bounds) / sizeof(gpointer));
455                         class->gc_descr = (gpointer)GC_make_descriptor ((GC_bitmap)&bitmap, 3);
456                 }
457         }
458         else {
459                 static int count = 0;
460                 MonoClass *p;
461                 guint32 pos;
462
463                 /* GC 6.1 has trouble handling 64 bit descriptors... */
464                 if ((class->instance_size / sizeof (gpointer)) > 30) {
465 /*                      printf ("TOO LARGE: %s %d.\n", class->name, class->instance_size / sizeof (gpointer)); */
466                         return;
467                 }
468
469                 bitmap = GC_HEADER_BITMAP;
470
471                 count ++;
472
473 /*              if (count > 442) */
474 /*                      return;  */
475
476 /*              printf("KLASS: %s.\n", class->name); */
477
478                 for (p = class; p != NULL; p = p->parent) {
479                 for (i = 0; i < p->field.count; ++i) {
480                         field = &p->fields [i];
481                         if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
482                                 continue;
483                         if (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)
484                                 return;
485
486                         pos = field->offset / sizeof (gpointer);
487                         
488                         if (field->type->byref)
489                                 return;
490
491                         switch (field->type->type) {
492                         case MONO_TYPE_BOOLEAN:
493                         case MONO_TYPE_I1:
494                         case MONO_TYPE_U1:
495                         case MONO_TYPE_I2:
496                         case MONO_TYPE_U2:
497                         case MONO_TYPE_CHAR:
498                         case MONO_TYPE_I4:
499                         case MONO_TYPE_U4:
500                         case MONO_TYPE_I8:
501                         case MONO_TYPE_U8:
502                         case MONO_TYPE_R4:
503                         case MONO_TYPE_R8:
504 /*                              printf ("F: %s %s %d %lld %llx.\n", class->name, field->name, field->offset, ((guint64)1) << pos, bitmap); */
505                                 break;
506                         case MONO_TYPE_I:
507                         case MONO_TYPE_STRING:
508                         case MONO_TYPE_SZARRAY:
509                         case MONO_TYPE_CLASS:
510                         case MONO_TYPE_OBJECT:
511                         case MONO_TYPE_ARRAY:
512                         case MONO_TYPE_PTR:
513                                 g_assert ((field->offset % sizeof(gpointer)) == 0);
514
515                                 bitmap |= ((guint64)1) << pos;
516 /*                              printf ("F: %s %s %d %d %lld %llx.\n", class->name, field->name, field->offset, pos, ((guint64)(1)) << pos, bitmap); */
517                                 break;
518                         case MONO_TYPE_VALUETYPE: {
519                                 MonoClass *fclass = field->type->data.klass;
520                                 if (!fclass->enumtype) {
521                                         mono_class_compute_gc_descriptor (fclass);
522                                         bitmap |= (fclass->gc_bitmap >> (sizeof (MonoObject) / sizeof (gpointer))) << pos;
523                                 }
524                                 break;
525                         }
526                         default:
527                                 return;
528                         }
529                 }
530                 }
531
532 /*              printf("CLASS: %s.%s -> %d %llx.\n", class->name_space, class->name, class->instance_size / sizeof (gpointer), bitmap); */
533                 class->gc_bitmap = bitmap;
534                 /* Convert to the format expected by GC_make_descriptor */
535                 bm [0] = (guint32)bitmap;
536                 bm [1] = (guint32)(bitmap >> 32);
537                 class->gc_descr = (gpointer)GC_make_descriptor ((GC_bitmap)&bm, class->instance_size / sizeof (gpointer));
538         }
539 }
540 #endif /* CREATION_SPEEDUP */
541
542 /**
543  * field_is_special_static:
544  * @fklass: The MonoClass to look up.
545  * @field: The MonoClassField describing the field.
546  *
547  * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
548  * SPECIAL_STATIC_NONE otherwise.
549  */
550 static gint32
551 field_is_special_static (MonoClass *fklass, MonoClassField *field)
552 {
553         MonoCustomAttrInfo *ainfo;
554         int i;
555         ainfo = mono_custom_attrs_from_field (fklass, field);
556         if (!ainfo)
557                 return FALSE;
558         for (i = 0; i < ainfo->num_attrs; ++i) {
559                 MonoClass *klass = ainfo->attrs [i].ctor->klass;
560                 if (klass->image == mono_defaults.corlib) {
561                         if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
562                                 mono_custom_attrs_free (ainfo);
563                                 return SPECIAL_STATIC_THREAD;
564                         }
565                         else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
566                                 mono_custom_attrs_free (ainfo);
567                                 return SPECIAL_STATIC_CONTEXT;
568                         }
569                 }
570         }
571         mono_custom_attrs_free (ainfo);
572         return SPECIAL_STATIC_NONE;
573 }
574
575 /**
576  * mono_class_vtable:
577  * @domain: the application domain
578  * @class: the class to initialize
579  *
580  * VTables are domain specific because we create domain specific code, and 
581  * they contain the domain specific static class data.
582  */
583 MonoVTable *
584 mono_class_vtable (MonoDomain *domain, MonoClass *class)
585 {
586         MonoVTable *vt = NULL;
587         MonoClassField *field;
588         char *t;
589         int i;
590         guint32 vtable_size;
591         guint32 cindex;
592         guint32 constant_cols [MONO_CONSTANT_SIZE];
593
594         g_assert (class);
595
596         vt = class->cached_vtable;
597         if (vt && vt->domain == domain)
598                 return vt;
599
600         mono_domain_lock (domain);
601         if ((vt = mono_g_hash_table_lookup (domain->class_vtable_hash, class))) {
602                 mono_domain_unlock (domain);
603                 return vt;
604         }
605         
606         if (!class->inited)
607                 mono_class_init (class);
608
609         mono_stats.used_class_count++;
610         mono_stats.class_vtable_size += sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
611
612         vtable_size = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
613
614         vt = mono_mempool_alloc0 (domain->mp,  vtable_size);
615
616         vt->klass = class;
617         vt->domain = domain;
618
619 #if CREATION_SPEEDUP
620         mono_class_compute_gc_descriptor (class);
621         if (domain != mono_get_root_domain ())
622                 /*
623                  * We can't use typed allocation in the non-root domains, since the
624                  * collector needs the GC descriptor stored in the vtable even after
625                  * the mempool containing the vtable is destroyed when the domain is
626                  * unloaded. An alternative might be to allocate vtables in the GC
627                  * heap, but this does not seem to work (it leads to crashes inside
628                  * libgc). If that approach is tried, two gc descriptors need to be
629                  * allocated for each class: one for the root domain, and one for all
630                  * other domains. The second descriptor should contain a bit for the
631                  * vtable field in MonoObject, since we can no longer assume the 
632                  * vtable is reachable by other roots after the appdomain is unloaded.
633                  */
634                 vt->gc_descr = GC_NO_DESCRIPTOR;
635         else
636                 vt->gc_descr = class->gc_descr;
637 #endif
638
639         if (class->class_size) {
640 #if HAVE_BOEHM_GC
641                 vt->data = GC_MALLOC (class->class_size + 8);
642                 /*vt->data = GC_debug_malloc (class->class_size + 8, class->name, 2);*/
643                 /*GC_register_finalizer (vt->data, vtable_finalizer, class->name, NULL, NULL);*/
644                 mono_g_hash_table_insert (domain->static_data_hash, class, vt->data);
645 #else
646                 vt->data = mono_mempool_alloc0 (domain->mp, class->class_size + 8);
647                 
648 #endif
649                 mono_stats.class_static_data_size += class->class_size + 8;
650         }
651
652         cindex = -1;
653         for (i = class->field.first; i < class->field.last; ++i) {
654                 field = &class->fields [i - class->field.first];
655                 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
656                         continue;
657                 if (mono_field_is_deleted (field))
658                         continue;
659                 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
660                         gint32 special_static = field_is_special_static (class, field);
661                         if (special_static != SPECIAL_STATIC_NONE) {
662                                 guint32 size, align, offset;
663                                 size = mono_type_size (field->type, &align);
664                                 offset = mono_alloc_special_static_data (special_static, size, align);
665                                 if (!domain->special_static_fields)
666                                         domain->special_static_fields = g_hash_table_new (NULL, NULL);
667                                 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
668                                 continue;
669                         }
670                 }
671                 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
672                         MonoClass *fklass = mono_class_from_mono_type (field->type);
673                         g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
674                         t = (char*)vt->data + field->offset;
675                         if (fklass->valuetype) {
676                                 memcpy (t, field->data, mono_class_value_size (fklass, NULL));
677                         } else {
678                                 /* it's a pointer type: add check */
679                                 g_assert (fklass->byval_arg.type == MONO_TYPE_PTR);
680                                 *t = *(char *)field->data;
681                         }
682                         continue;
683                 }
684                 if (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
685                         continue;
686
687                 
688                 if (!field->data) {
689                         cindex = mono_metadata_get_constant_index (class->image, MONO_TOKEN_FIELD_DEF | (i + 1), cindex + 1);
690                         g_assert (cindex);
691                         g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
692
693                         mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
694                         field->def_type = constant_cols [MONO_CONSTANT_TYPE];
695                         field->data = (gpointer)mono_metadata_blob_heap (class->image, constant_cols [MONO_CONSTANT_VALUE]);
696                 }
697                 
698                 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL))
699                         get_default_field_value (domain, field, (char*)vt->data + field->offset);
700         }
701
702         vt->max_interface_id = class->max_interface_id;
703         
704         vt->interface_offsets = mono_mempool_alloc0 (domain->mp, 
705                 sizeof (gpointer) * (class->max_interface_id + 1));
706
707         /* initialize interface offsets */
708         for (i = 0; i <= class->max_interface_id; ++i) {
709                 int slot = class->interface_offsets [i];
710                 if (slot >= 0)
711                         vt->interface_offsets [i] = &(vt->vtable [slot]);
712         }
713
714         /* 
715          * arch_create_jit_trampoline () can recursively call this function again
716          * because it compiles icall methods right away.
717          */
718         mono_g_hash_table_insert (domain->class_vtable_hash, class, vt);
719         if (!class->cached_vtable)
720                 class->cached_vtable = vt;
721
722         /* initialize vtable */
723         for (i = 0; i < class->vtable_size; ++i) {
724                 MonoMethod *cm;
725                
726                 if ((cm = class->vtable [i])) {
727                         if (cm->signature->generic_param_count)
728                                 vt->vtable [i] = cm;
729                         else
730                                 vt->vtable [i] = arch_create_jit_trampoline (cm);
731                 }
732         }
733
734         mono_domain_unlock (domain);
735
736         /* make sure the the parent is initialized */
737         if (class->parent)
738                 mono_class_vtable (domain, class->parent);
739
740         vt->type = mono_type_get_object (domain, &class->byval_arg);
741         if (class->contextbound)
742                 vt->remote = 1;
743         else
744                 vt->remote = 0;
745
746         return vt;
747 }
748
749 /**
750  * mono_class_proxy_vtable:
751  * @domain: the application domain
752  * @remove_class: the remote class
753  *
754  * Creates a vtable for transparent proxies. It is basically
755  * a copy of the real vtable of the class wrapped in @remote_class,
756  * but all function pointers invoke the remoting functions, and
757  * vtable->klass points to the transparent proxy class, and not to @class.
758  */
759 static MonoVTable *
760 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
761 {
762         MonoVTable *vt, *pvt;
763         int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
764         MonoClass *k;
765         MonoClass *class = remote_class->proxy_class;
766
767         vt = mono_class_vtable (domain, class);
768         max_interface_id = vt->max_interface_id;
769
770         /* Calculate vtable space for extra interfaces */
771         for (j = 0; j < remote_class->interface_count; j++) {
772                 MonoClass* iclass = remote_class->interfaces[j];
773                 int method_count = iclass->method.count;
774         
775                 if (iclass->interface_id <= class->max_interface_id && class->interface_offsets[iclass->interface_id] != 0) 
776                         continue;       /* interface implemented by the class */
777
778                 for (i = 0; i < iclass->interface_count; i++)
779                         method_count += iclass->interfaces[i]->method.count;
780
781                 extra_interface_vtsize += method_count * sizeof (gpointer);
782                 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
783         }
784
785         vtsize = sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
786
787         mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
788
789         pvt = mono_mempool_alloc (domain->mp, vtsize + extra_interface_vtsize);
790         memcpy (pvt, vt, vtsize);
791
792         pvt->klass = mono_defaults.transparent_proxy_class;
793
794         /* initialize vtable */
795         for (i = 0; i < class->vtable_size; ++i) {
796                 MonoMethod *cm;
797                     
798                 if ((cm = class->vtable [i]))
799                         pvt->vtable [i] = arch_create_remoting_trampoline (cm, target_type);
800         }
801
802         if (class->flags & TYPE_ATTRIBUTE_ABSTRACT)
803         {
804                 /* create trampolines for abstract methods */
805                 for (k = class; k; k = k->parent) {
806                         for (i = 0; i < k->method.count; i++) {
807                                 int slot = k->methods [i]->slot;
808                                 if (!pvt->vtable [slot]) 
809                                         pvt->vtable [slot] = arch_create_remoting_trampoline (k->methods[i], target_type);
810                         }
811                 }
812         }
813
814         pvt->max_interface_id = max_interface_id;
815         pvt->interface_offsets = mono_mempool_alloc0 (domain->mp, 
816                         sizeof (gpointer) * (max_interface_id + 1));
817
818         /* initialize interface offsets */
819         for (i = 0; i <= class->max_interface_id; ++i) {
820                 int slot = class->interface_offsets [i];
821                 if (slot >= 0)
822                         pvt->interface_offsets [i] = &(pvt->vtable [slot]);
823         }
824
825         if (remote_class->interface_count > 0)
826         {
827                 int slot = class->vtable_size;
828                 MonoClass* interf;
829                 MonoClass* iclass;
830                 int n;
831
832                 /* Create trampolines for the methods of the interfaces */
833                 for (n = 0; n < remote_class->interface_count; n++) 
834                 {
835                         iclass = remote_class->interfaces[n];
836                         if (iclass->interface_id <= class->max_interface_id && class->interface_offsets[iclass->interface_id] != 0) 
837                                 continue;       /* interface implemented by the class */
838                 
839                         i = -1;
840                         interf = iclass;
841                         do {
842                                 pvt->interface_offsets [interf->interface_id] = &pvt->vtable [slot];
843         
844                                 for (j = 0; j < interf->method.count; ++j) {
845                                         MonoMethod *cm = interf->methods [j];
846                                         pvt->vtable [slot + j] = arch_create_remoting_trampoline (cm, target_type);
847                                 }
848                                 slot += interf->method.count;
849                                 if (++i < iclass->interface_count) interf = iclass->interfaces[i];
850                                 else interf = NULL;
851                                 
852                         } while (interf);
853                 }
854         }
855
856         return pvt;
857 }
858
859 /**
860  * mono_remote_class:
861  * @domain: the application domain
862  * @class_name: name of the remote class
863  *
864  * Creates and initializes a MonoRemoteClass object for a remote type. 
865  * 
866  */
867 MonoRemoteClass*
868 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
869 {
870         MonoRemoteClass *rc;
871
872         mono_domain_lock (domain);
873         rc = mono_g_hash_table_lookup (domain->proxy_vtable_hash, class_name);
874
875         if (rc) {
876                 mono_domain_unlock (domain);
877                 return rc;
878         }
879
880         rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass));
881         rc->default_vtable = NULL;
882         rc->xdomain_vtable = NULL;
883         rc->interface_count = 0;
884         rc->interfaces = NULL;
885         rc->proxy_class = mono_defaults.marshalbyrefobject_class;
886         rc->proxy_class_name = mono_string_to_utf8 (class_name);
887
888         mono_g_hash_table_insert (domain->proxy_vtable_hash, class_name, rc);
889         mono_upgrade_remote_class (domain, rc, proxy_class);
890
891         mono_domain_unlock (domain);
892
893         return rc;
894 }
895
896 static void
897 extend_interface_array (MonoDomain *domain, MonoRemoteClass *remote_class, int amount)
898 {
899         /* Extends the array of interfaces. Memory is extended using blocks of 5 pointers */
900
901         int current_size = ((remote_class->interface_count / 5) + 1) * 5;
902         remote_class->interface_count += amount;
903
904         if (remote_class->interface_count > current_size || remote_class->interfaces == NULL) 
905         {
906                 int new_size = ((remote_class->interface_count / 5) + 1) * 5;
907                 MonoClass **new_array = mono_mempool_alloc (domain->mp, new_size * sizeof (MonoClass*));
908         
909                 if (remote_class->interfaces != NULL)
910                         memcpy (new_array, remote_class->interfaces, current_size * sizeof (MonoClass*));
911                 
912                 remote_class->interfaces = new_array;
913         }
914 }
915
916 gpointer
917 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
918 {
919         if (rp->target_domain_id != -1) {
920                 if (remote_class->xdomain_vtable == NULL)
921                         remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
922                 return remote_class->xdomain_vtable;
923         }
924         if (remote_class->default_vtable == NULL)
925                 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
926         
927         return remote_class->default_vtable;
928 }
929
930
931 /**
932  * mono_upgrade_remote_class:
933  * @domain: the application domain
934  * @remote_class: the remote class
935  * @klass: class to which the remote class can be casted.
936  *
937  * Updates the vtable of the remote class by adding the necessary method slots
938  * and interface offsets so it can be safely casted to klass. klass can be a
939  * class or an interface.
940  */
941 void mono_upgrade_remote_class (MonoDomain *domain, MonoRemoteClass *remote_class, MonoClass *klass)
942 {
943         gboolean redo_vtable;
944
945         mono_domain_lock (domain);
946
947         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
948                 int i;
949                 redo_vtable = TRUE;
950                 for (i = 0; i < remote_class->interface_count; i++)
951                         if (remote_class->interfaces[i] == klass) redo_vtable = FALSE;
952                                 
953                 if (redo_vtable) {
954                         extend_interface_array (domain, remote_class, 1);
955                         remote_class->interfaces [remote_class->interface_count-1] = klass;
956                 }
957         }
958         else {
959                 redo_vtable = (remote_class->proxy_class != klass);
960                 remote_class->proxy_class = klass;
961         }
962
963         if (redo_vtable) {
964                 remote_class->default_vtable = NULL;
965                 remote_class->xdomain_vtable = NULL;
966         }
967 /*
968         int n;
969         printf ("remote class upgrade - class:%s num-interfaces:%d\n", remote_class->proxy_class_name, remote_class->interface_count);
970         
971         for (n=0; n<remote_class->interface_count; n++)
972                 printf ("  I:%s\n", remote_class->interfaces[n]->name);
973 */
974
975         mono_domain_unlock (domain);
976 }
977
978 /**
979  * mono_object_get_virtual_method:
980  * @obj: object to operate on.
981  * @method: method 
982  *
983  * Retrieves the MonoMethod that would be called on obj if obj is passed as
984  * the instance of a callvirt of method.
985  */
986 MonoMethod*
987 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
988 {
989         MonoClass *klass;
990         MonoMethod **vtable;
991         gboolean is_proxy;
992         MonoMethod *res = NULL;
993
994         klass = mono_object_class (obj);
995         if (klass == mono_defaults.transparent_proxy_class) {
996                 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
997                 is_proxy = TRUE;
998         } else {
999                 is_proxy = FALSE;
1000         }
1001
1002         if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
1003                         return method;
1004
1005         vtable = klass->vtable;
1006
1007         /* check method->slot is a valid index: perform isinstance? */
1008         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1009                 if (!is_proxy)
1010                         res = vtable [klass->interface_offsets [method->klass->interface_id] + method->slot];
1011         } else {
1012                 if (method->slot != -1)
1013                         res = vtable [method->slot];
1014         }
1015
1016         if (is_proxy) {
1017                 if (!res) res = method;   /* It may be an interface or abstract class method */
1018                 res = mono_marshal_get_remoting_invoke (res);
1019         }
1020
1021         g_assert (res);
1022         
1023         return res;
1024 }
1025
1026 static MonoObject*
1027 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
1028 {
1029         g_error ("runtime invoke called on uninitialized runtime");
1030         return NULL;
1031 }
1032
1033 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
1034
1035 /**
1036  * mono_runtime_invoke:
1037  * @method: method to invoke
1038  * @obJ: object instance
1039  * @params: arguments to the method
1040  * @exc: exception information.
1041  *
1042  * Invokes the method represented by @method on the object @obj.
1043  *
1044  * obj is the 'this' pointer, it should be NULL for static
1045  * methods, a MonoObject* for object instances and a pointer to
1046  * the value type for value types.
1047  *
1048  * The params array contains the arguments to the method with the
1049  * same convention: MonoObject* pointers for object instances and
1050  * pointers to the value type otherwise. 
1051  * 
1052  * From unmanaged code you'll usually use the
1053  * mono_runtime_invoke() variant.
1054  *
1055  * Note that this function doesn't handle virtual methods for
1056  * you, it will exec the exact method you pass: we still need to
1057  * expose a function to lookup the derived class implementation
1058  * of a virtual method (there are examples of this in the code,
1059  * though).
1060  * 
1061  * You can pass NULL as the exc argument if you don't want to
1062  * catch exceptions, otherwise, *exc will be set to the exception
1063  * thrown, if any.  if an exception is thrown, you can't use the
1064  * MonoObject* result from the function.
1065  * 
1066  * If the method returns a value type, it is boxed in an object
1067  * reference.
1068  */
1069 MonoObject*
1070 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
1071 {
1072         return default_mono_runtime_invoke (method, obj, params, exc);
1073 }
1074
1075 static void
1076 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
1077 {
1078         int t;
1079         if (type->byref) {
1080                 gpointer *p = (gpointer*)dest;
1081                 *p = value;
1082                 return;
1083         }
1084         t = type->type;
1085 handle_enum:
1086         switch (t) {
1087         case MONO_TYPE_BOOLEAN:
1088         case MONO_TYPE_I1:
1089         case MONO_TYPE_U1: {
1090                 guint8 *p = (guint8*)dest;
1091                 *p = *(guint8*)value;
1092                 return;
1093         }
1094         case MONO_TYPE_I2:
1095         case MONO_TYPE_U2:
1096         case MONO_TYPE_CHAR: {
1097                 guint16 *p = (guint16*)dest;
1098                 *p = *(guint16*)value;
1099                 return;
1100         }
1101 #if SIZEOF_VOID_P == 4
1102         case MONO_TYPE_I:
1103         case MONO_TYPE_U:
1104 #endif
1105         case MONO_TYPE_I4:
1106         case MONO_TYPE_U4: {
1107                 gint32 *p = (gint32*)dest;
1108                 *p = *(gint32*)value;
1109                 return;
1110         }
1111 #if SIZEOF_VOID_P == 8
1112         case MONO_TYPE_I:
1113         case MONO_TYPE_U:
1114 #endif
1115         case MONO_TYPE_I8:
1116         case MONO_TYPE_U8: {
1117                 gint64 *p = (gint64*)dest;
1118                 *p = *(gint64*)value;
1119                 return;
1120         }
1121         case MONO_TYPE_R4: {
1122                 float *p = (float*)dest;
1123                 *p = *(float*)value;
1124                 return;
1125         }
1126         case MONO_TYPE_R8: {
1127                 double *p = (double*)dest;
1128                 *p = *(double*)value;
1129                 return;
1130         }
1131         case MONO_TYPE_STRING:
1132         case MONO_TYPE_SZARRAY:
1133         case MONO_TYPE_CLASS:
1134         case MONO_TYPE_OBJECT:
1135         case MONO_TYPE_ARRAY:
1136         case MONO_TYPE_PTR: {
1137                 gpointer *p = (gpointer*)dest;
1138                 *p = deref_pointer? *(gpointer*)value: value;
1139                 return;
1140         }
1141         case MONO_TYPE_VALUETYPE:
1142                 if (type->data.klass->enumtype) {
1143                         t = type->data.klass->enum_basetype->type;
1144                         goto handle_enum;
1145                 } else {
1146                         int size;
1147                         size = mono_class_value_size (type->data.klass, NULL);
1148                         memcpy (dest, value, size);
1149                 }
1150                 return;
1151         default:
1152                 g_warning ("got type %x", type->type);
1153                 g_assert_not_reached ();
1154         }
1155 }
1156
1157 /**
1158  * mono_field_set_value:
1159  * @obj: Instance object
1160  * @field: MonoClassField describing the field to set
1161  * @value: The value to be set
1162  *
1163  * Sets the value of the field described by @field in the object instance @obj
1164  * to the value passed in @value.
1165  *
1166  * The value must be on the native format of the field type. 
1167  */
1168 void
1169 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
1170 {
1171         void *dest;
1172
1173         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
1174
1175         dest = (char*)obj + field->offset;
1176         set_value (field->type, dest, value, FALSE);
1177 }
1178
1179 /**
1180  * mono_field_static_set_value:
1181  * @field: MonoClassField describing the field to set
1182  * @value: The value to be set
1183  *
1184  * Sets the value of the static field described by @field
1185  * to the value passed in @value.
1186  *
1187  * The value must be on the native format of the field type. 
1188  */
1189 void
1190 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
1191 {
1192         void *dest;
1193
1194         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
1195         /* you cant set a constant! */
1196         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
1197         
1198         dest = (char*)vt->data + field->offset;
1199         set_value (field->type, dest, value, FALSE);
1200 }
1201
1202 /**
1203  * mono_field_get_value:
1204  * @obj: Object instance
1205  * @field: MonoClassField describing the field to fetch information from
1206  * @value: pointer to the location where the value will be stored
1207  *
1208  * Use this routine to get the value of the field @field in the object
1209  * passed.
1210  *
1211  * The pointer provided by value must be of the field type, for reference
1212  * types this is a MonoObject*, for value types its the actual pointer to
1213  * the value type.
1214  *
1215  * For example:
1216  *     int i;
1217  *     mono_field_get_value (obj, int_field, &i);
1218  */
1219 void
1220 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
1221 {
1222         void *src;
1223
1224         g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
1225
1226         src = (char*)obj + field->offset;
1227         set_value (field->type, value, src, TRUE);
1228 }
1229
1230 /**
1231  * mono_field_get_value_object:
1232  * @domain: domain where the object will be created (if boxing)
1233  * @field: MonoClassField describing the field to fetch information from
1234  * @obj: The object instance for the field.
1235  *
1236  * Returns: a new MonoObject with the value from the given field.  If the
1237  * field represents a value type, the value is boxed.
1238  *
1239  */
1240 MonoObject *
1241 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
1242 {       
1243         MonoObject *o;
1244         MonoClass *klass;
1245         MonoVTable *vtable = NULL;
1246         gchar *v;
1247         gboolean is_static = FALSE;
1248         gboolean is_ref = FALSE;
1249
1250         switch (field->type->type) {
1251         case MONO_TYPE_STRING:
1252         case MONO_TYPE_OBJECT:
1253         case MONO_TYPE_CLASS:
1254         case MONO_TYPE_ARRAY:
1255         case MONO_TYPE_SZARRAY:
1256                 is_ref = TRUE;
1257                 break;
1258         case MONO_TYPE_U1:
1259         case MONO_TYPE_I1:
1260         case MONO_TYPE_BOOLEAN:
1261         case MONO_TYPE_U2:
1262         case MONO_TYPE_I2:
1263         case MONO_TYPE_CHAR:
1264         case MONO_TYPE_U:
1265         case MONO_TYPE_I:
1266         case MONO_TYPE_U4:
1267         case MONO_TYPE_I4:
1268         case MONO_TYPE_R4:
1269         case MONO_TYPE_U8:
1270         case MONO_TYPE_I8:
1271         case MONO_TYPE_R8:
1272         case MONO_TYPE_VALUETYPE:
1273                 is_ref = field->type->byref;
1274                 break;
1275         default:
1276                 g_error ("type 0x%x not handled in "
1277                          "mono_field_get_value_object", field->type->type);
1278                 return NULL;
1279         }
1280
1281         if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
1282                 is_static = TRUE;
1283                 vtable = mono_class_vtable (domain, field->parent);
1284                 if (!vtable->initialized)
1285                         mono_runtime_class_init (vtable);
1286         }
1287         
1288         if (is_ref) {
1289                 if (is_static) {
1290                         mono_field_static_get_value (vtable, field, &o);
1291                 } else {
1292                         mono_field_get_value (obj, field, &o);
1293                 }
1294                 return o;
1295         }
1296
1297         /* boxed value type */
1298         klass = mono_class_from_mono_type (field->type);
1299         o = mono_object_new (domain, klass);
1300         v = ((gchar *) o) + sizeof (MonoObject);
1301         if (is_static) {
1302                 mono_field_static_get_value (vtable, field, v);
1303         } else {
1304                 mono_field_get_value (obj, field, v);
1305         }
1306
1307         return o;
1308 }
1309
1310 int
1311 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
1312 {
1313         int retval = 0;
1314         const char *p = blob;
1315         mono_metadata_decode_blob_size (p, &p);
1316
1317         switch (type) {
1318         case MONO_TYPE_BOOLEAN:
1319         case MONO_TYPE_U1:
1320         case MONO_TYPE_I1:
1321                 *(guint8 *) value = *p;
1322                 break;
1323         case MONO_TYPE_CHAR:
1324         case MONO_TYPE_U2:
1325         case MONO_TYPE_I2:
1326                 *(guint16*) value = read16 (p);
1327                 break;
1328         case MONO_TYPE_U4:
1329         case MONO_TYPE_I4:
1330                 *(guint32*) value = read32 (p);
1331                 break;
1332         case MONO_TYPE_U8:
1333         case MONO_TYPE_I8:
1334                 *(guint64*) value = read64 (p);
1335                 break;
1336         case MONO_TYPE_R4:
1337                 readr4 (p, (float*) value);
1338                 break;
1339         case MONO_TYPE_R8:
1340                 readr8 (p, (double*) value);
1341                 break;
1342         case MONO_TYPE_STRING:
1343                 *(gpointer*) value = mono_ldstr_metdata_sig (domain, blob);
1344                 break;
1345         case MONO_TYPE_CLASS:
1346                 *(gpointer*) value = NULL;
1347                 break;
1348         default:
1349                 retval = -1;
1350                 g_warning ("type 0x%02x should not be in constant table", type);
1351         }
1352         return retval;
1353 }
1354
1355 static void
1356 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
1357 {
1358         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
1359         mono_get_constant_value_from_blob (domain, field->def_type, field->data, value);
1360 }
1361
1362 /**
1363  * mono_field_static_get_value:
1364  * @vt: vtable to the object
1365  * @field: MonoClassField describing the field to fetch information from
1366  * @value: where the value is returned
1367  *
1368  * Use this routine to get the value of the static field @field value.
1369  *
1370  * The pointer provided by value must be of the field type, for reference
1371  * types this is a MonoObject*, for value types its the actual pointer to
1372  * the value type.
1373  *
1374  * For example:
1375  *     int i;
1376  *     mono_field_static_get_value (vt, int_field, &i);
1377  */
1378 void
1379 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
1380 {
1381         void *src;
1382
1383         g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
1384         
1385         if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
1386                 get_default_field_value (vt->domain, field, value);
1387                 return;
1388         }
1389
1390         src = (char*)vt->data + field->offset;
1391         set_value (field->type, value, src, TRUE);
1392 }
1393
1394 /**
1395  * mono_property_set_value:
1396  * @prop: MonoProperty to set
1397  * @obj: instance object on which to act
1398  * @params: parameters to pass to the propery
1399  * @exc: optional exception
1400  *
1401  * Invokes the property's set method with the given arguments on the
1402  * object instance obj (or NULL for static properties). 
1403  * 
1404  * You can pass NULL as the exc argument if you don't want to
1405  * catch exceptions, otherwise, *exc will be set to the exception
1406  * thrown, if any.  if an exception is thrown, you can't use the
1407  * MonoObject* result from the function.
1408  */
1409 void
1410 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
1411 {
1412         default_mono_runtime_invoke (prop->set, obj, params, exc);
1413 }
1414
1415 /**
1416  * mono_property_get_value:
1417  * @prop: MonoProperty to fetch
1418  * @obj: instance object on which to act
1419  * @params: parameters to pass to the propery
1420  * @exc: optional exception
1421  *
1422  * Invokes the property's get method with the given arguments on the
1423  * object instance obj (or NULL for static properties). 
1424  * 
1425  * You can pass NULL as the exc argument if you don't want to
1426  * catch exceptions, otherwise, *exc will be set to the exception
1427  * thrown, if any.  if an exception is thrown, you can't use the
1428  * MonoObject* result from the function.
1429  *
1430  * Returns: the value from invoking the get method on the property.
1431  */
1432 MonoObject*
1433 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
1434 {
1435         return default_mono_runtime_invoke (prop->get, obj, params, exc);
1436 }
1437
1438
1439 /**
1440  * mono_get_delegate_invoke:
1441  * @klass: The delegate class
1442  *
1443  * Returns: the MonoMethod for the "Invoke" method in the delegate klass
1444  */
1445 MonoMethod *
1446 mono_get_delegate_invoke (MonoClass *klass)
1447 {
1448         MonoMethod *im;
1449         int i;
1450
1451         im = NULL;
1452
1453         for (i = 0; i < klass->method.count; ++i) {
1454                 if (klass->methods [i]->name[0] == 'I' && 
1455                     !strcmp ("Invoke", klass->methods [i]->name)) {
1456                         im = klass->methods [i];
1457                 }
1458         }
1459
1460         g_assert (im);
1461
1462         return im;
1463 }
1464
1465 /**
1466  * mono_runtime_delegate_invoke:
1467  * @delegate: pointer to a delegate object.
1468  * @params: parameters for the delegate.
1469  * @exc: Pointer to the exception result.
1470  *
1471  * Invokes the delegate method @delegate with the parameters provided.
1472  *
1473  * You can pass NULL as the exc argument if you don't want to
1474  * catch exceptions, otherwise, *exc will be set to the exception
1475  * thrown, if any.  if an exception is thrown, you can't use the
1476  * MonoObject* result from the function.
1477  */
1478 MonoObject*
1479 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
1480 {
1481         MonoMethod *im;
1482
1483         im = mono_get_delegate_invoke (delegate->vtable->klass);
1484         g_assert (im);
1485
1486         return mono_runtime_invoke (im, delegate, params, exc);
1487 }
1488
1489 static MonoArray* main_args;
1490
1491 /**
1492  * mono_runtime_get_main_args:
1493  *
1494  * Returns: a MonoArray with the arguments passed to the main program
1495  */
1496 MonoArray*
1497 mono_runtime_get_main_args (void)
1498 {
1499         return main_args;
1500 }
1501
1502 static void
1503 fire_process_exit_event (void)
1504 {
1505         MonoClassField *field;
1506         MonoDomain *domain = mono_domain_get ();
1507         gpointer pa [2];
1508         MonoObject *delegate, *exc;
1509         
1510         field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
1511         g_assert (field);
1512
1513         if (domain != mono_get_root_domain ())
1514                 return;
1515
1516         delegate = *(MonoObject **)(((char *)domain->domain) + field->offset); 
1517         if (delegate == NULL)
1518                 return;
1519
1520         pa [0] = domain;
1521         pa [1] = NULL;
1522         mono_runtime_delegate_invoke (delegate, pa, &exc);
1523 }
1524
1525 /**
1526  * mono_runtime_run_main:
1527  * @method: the method to start the application with (usually Main)
1528  * @argc: number of arguments from the command line
1529  * @argv: array of strings from the command line
1530  * @exc: excetption results
1531  *
1532  * Execute a standard Main() method (argc/argv contains the
1533  * executable name). This method also sets the command line argument value
1534  * needed by System.Environment.
1535  *
1536  * 
1537  */
1538 int
1539 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
1540                        MonoObject **exc)
1541 {
1542         int i;
1543         MonoArray *args = NULL;
1544         MonoDomain *domain = mono_domain_get ();
1545         gchar *utf8_fullpath;
1546         int result;
1547
1548         main_thread = mono_thread_current ();
1549
1550         main_args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
1551
1552         if (!g_path_is_absolute (argv [0])) {
1553                 gchar *basename = g_path_get_basename (argv [0]);
1554                 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
1555                                                     basename,
1556                                                     NULL);
1557
1558                 utf8_fullpath = mono_utf8_from_external (fullpath);
1559                 if(utf8_fullpath == NULL) {
1560                         /* Printing the arg text will cause glib to
1561                          * whinge about "Invalid UTF-8", but at least
1562                          * its relevant, and shows the problem text
1563                          * string.
1564                          */
1565                         g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
1566                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1567                         exit (-1);
1568                 }
1569
1570                 g_free (fullpath);
1571                 g_free (basename);
1572         } else {
1573                 utf8_fullpath = mono_utf8_from_external (argv[0]);
1574                 if(utf8_fullpath == NULL) {
1575                         g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
1576                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1577                         exit (-1);
1578                 }
1579         }
1580                 
1581         mono_array_set (main_args, gpointer, 0, mono_string_new (domain, utf8_fullpath));
1582         g_free (utf8_fullpath);
1583
1584         for (i = 1; i < argc; ++i) {
1585                 gchar *utf8_arg;
1586                 MonoString *arg;
1587
1588                 utf8_arg=mono_utf8_from_external (argv[i]);
1589                 if(utf8_arg==NULL) {
1590                         /* Ditto the comment about Invalid UTF-8 here */
1591                         g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
1592                         g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
1593                         exit (-1);
1594                 }
1595                 
1596                 arg = mono_string_new (domain, utf8_arg);
1597                 mono_array_set (main_args, gpointer, i, arg);
1598                 g_free (utf8_arg);
1599         }
1600         argc--;
1601         argv++;
1602         if (method->signature->param_count) {
1603                 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
1604                 for (i = 0; i < argc; ++i) {
1605                         /* The encodings should all work, given that
1606                          * we've checked all these args for the
1607                          * main_args array.
1608                          */
1609                         gchar *str = mono_utf8_from_external (argv [i]);
1610                         MonoString *arg = mono_string_new (domain, str);
1611                         mono_array_set (args, gpointer, i, arg);
1612                         g_free (str);
1613                 }
1614         } else {
1615                 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
1616         }
1617         
1618         mono_assembly_set_main (method->klass->image->assembly);
1619
1620         result = mono_runtime_exec_main (method, args, exc);
1621         fire_process_exit_event ();
1622         return result;
1623 }
1624
1625 /* Used in mono_unhandled_exception */
1626 static MonoObject *
1627 create_unhandled_exception_eventargs (MonoObject *exc)
1628 {
1629         MonoClass *klass;
1630         gpointer args [2];
1631         MonoMethod *method = NULL;
1632         MonoBoolean is_terminating = TRUE;
1633         MonoObject *obj;
1634         gint i;
1635
1636         klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
1637         g_assert (klass);
1638
1639         mono_class_init (klass);
1640
1641         /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
1642         for (i = 0; i < klass->method.count; ++i) {
1643                 method = klass->methods [i];
1644                 if (!strcmp (".ctor", method->name) &&
1645                     method->signature->param_count == 2 &&
1646                     method->flags & METHOD_ATTRIBUTE_PUBLIC)
1647                         break;
1648                 method = NULL;
1649         }
1650
1651         g_assert (method);
1652
1653         args [0] = exc;
1654         args [1] = &is_terminating;
1655
1656         obj = mono_object_new (mono_domain_get (), klass);
1657         mono_runtime_invoke (method, obj, args, NULL);
1658
1659         return obj;
1660 }
1661
1662 /**
1663  * mono_unhandled_exception:
1664  * @exc: exception thrown
1665  *
1666  * This is a VM internal routine.
1667  *
1668  * We call this function when we detect an unhandled exception
1669  * in the default domain.
1670  *
1671  * It invokes the * UnhandledException event in AppDomain or prints
1672  * a warning to the console 
1673  */
1674 void
1675 mono_unhandled_exception (MonoObject *exc)
1676 {
1677         MonoDomain *domain = mono_domain_get ();
1678         MonoClassField *field;
1679         MonoObject *delegate;
1680
1681         field=mono_class_get_field_from_name(mono_defaults.appdomain_class, 
1682                                              "UnhandledException");
1683         g_assert (field);
1684
1685         if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
1686                 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset); 
1687
1688                 /* set exitcode only in the main thread */
1689                 if (mono_thread_current () == main_thread)
1690                         mono_environment_exitcode_set (1);
1691                 if (domain != mono_get_root_domain () || !delegate) {
1692                         mono_print_unhandled_exception (exc);
1693                 } else {
1694                         MonoObject *e = NULL;
1695                         gpointer pa [2];
1696
1697                         pa [0] = domain->domain;
1698                         pa [1] = create_unhandled_exception_eventargs (exc);
1699                         mono_runtime_delegate_invoke (delegate, pa, &e);
1700                         
1701                         if (e) {
1702                                 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
1703                                 g_warning ("exception inside UnhandledException handler: %s\n", msg);
1704                                 g_free (msg);
1705                         }
1706                 }
1707         }
1708 }
1709
1710 /*
1711  * Launch a new thread to start all setup that requires managed code
1712  * to be executed.
1713  *
1714  * main_func is called back from the thread with main_args as the
1715  * parameter.  The callback function is expected to start Main()
1716  * eventually.  This function then waits for all managed threads to
1717  * finish.
1718  */
1719 void
1720 mono_runtime_exec_managed_code (MonoDomain *domain,
1721                                 MonoMainThreadFunc main_func,
1722                                 gpointer main_args)
1723 {
1724         mono_thread_create (domain, main_func, main_args);
1725
1726         mono_thread_manage ();
1727 }
1728
1729 /*
1730  * Execute a standard Main() method (args doesn't contain the
1731  * executable name).
1732  */
1733 int
1734 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
1735 {
1736         MonoDomain *domain;
1737         gpointer pa [1];
1738         int rval;
1739
1740         g_assert (args);
1741
1742         pa [0] = args;
1743
1744         domain = mono_object_domain (args);
1745         if (!domain->entry_assembly) {
1746                 gchar *str;
1747                 gchar *config_suffix;
1748                 MonoAssembly *assembly;
1749
1750                 assembly = method->klass->image->assembly;
1751                 domain->entry_assembly = assembly;
1752                 domain->setup->application_base = mono_string_new (domain, assembly->basedir);
1753
1754                 config_suffix = g_strconcat (assembly->aname.name, ".exe.config", NULL);
1755                 str = g_build_filename (assembly->basedir, config_suffix, NULL);
1756                 g_free (config_suffix);
1757                 domain->setup->configuration_file = mono_string_new (domain, str);
1758                 g_free (str);
1759         }
1760
1761         /* FIXME: check signature of method */
1762         if (method->signature->ret->type == MONO_TYPE_I4) {
1763                 MonoObject *res;
1764                 res = mono_runtime_invoke (method, NULL, pa, exc);
1765                 if (!exc || !*exc)
1766                         rval = *(guint32 *)((char *)res + sizeof (MonoObject));
1767                 else
1768                         rval = -1;
1769
1770                 mono_environment_exitcode_set (rval);
1771         } else {
1772                 mono_runtime_invoke (method, NULL, pa, exc);
1773                 if (!exc || !*exc)
1774                         rval = 0;
1775                 else {
1776                         /* If the return type of Main is void, only
1777                          * set the exitcode if an exception was thrown
1778                          * (we don't want to blow away an
1779                          * explicitly-set exit code)
1780                          */
1781                         rval = -1;
1782                         mono_environment_exitcode_set (rval);
1783                 }
1784         }
1785
1786         return rval;
1787 }
1788
1789 /**
1790  * mono_install_runtime_invoke:
1791  * @func: Function to install
1792  *
1793  * This is a VM internal routine
1794  */
1795 void
1796 mono_install_runtime_invoke (MonoInvokeFunc func)
1797 {
1798         default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
1799 }
1800
1801 /**
1802  * mono_runtime_invoke_array:
1803  * @method: method to invoke
1804  * @obJ: object instance
1805  * @params: arguments to the method
1806  * @exc: exception information.
1807  *
1808  * Invokes the method represented by @method on the object @obj.
1809  *
1810  * obj is the 'this' pointer, it should be NULL for static
1811  * methods, a MonoObject* for object instances and a pointer to
1812  * the value type for value types.
1813  *
1814  * The params array contains the arguments to the method with the
1815  * same convention: MonoObject* pointers for object instances and
1816  * pointers to the value type otherwise. The _invoke_array
1817  * variant takes a C# object[] as the params argument (MonoArray
1818  * *params): in this case the value types are boxed inside the
1819  * respective reference representation.
1820  * 
1821  * From unmanaged code you'll usually use the
1822  * mono_runtime_invoke() variant.
1823  *
1824  * Note that this function doesn't handle virtual methods for
1825  * you, it will exec the exact method you pass: we still need to
1826  * expose a function to lookup the derived class implementation
1827  * of a virtual method (there are examples of this in the code,
1828  * though).
1829  * 
1830  * You can pass NULL as the exc argument if you don't want to
1831  * catch exceptions, otherwise, *exc will be set to the exception
1832  * thrown, if any.  if an exception is thrown, you can't use the
1833  * MonoObject* result from the function.
1834  * 
1835  * If the method returns a value type, it is boxed in an object
1836  * reference.
1837  */
1838 MonoObject*
1839 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
1840                            MonoObject **exc)
1841 {
1842         MonoMethodSignature *sig = method->signature;
1843         gpointer *pa = NULL;
1844         int i;
1845                 
1846         if (NULL != params) {
1847                 pa = alloca (sizeof (gpointer) * mono_array_length (params));
1848                 for (i = 0; i < mono_array_length (params); i++) {
1849                         if (sig->params [i]->byref) {
1850                                 /* nothing to do */
1851                         }
1852
1853                         switch (sig->params [i]->type) {
1854                         case MONO_TYPE_U1:
1855                         case MONO_TYPE_I1:
1856                         case MONO_TYPE_BOOLEAN:
1857                         case MONO_TYPE_U2:
1858                         case MONO_TYPE_I2:
1859                         case MONO_TYPE_CHAR:
1860                         case MONO_TYPE_U:
1861                         case MONO_TYPE_I:
1862                         case MONO_TYPE_U4:
1863                         case MONO_TYPE_I4:
1864                         case MONO_TYPE_U8:
1865                         case MONO_TYPE_I8:
1866                         case MONO_TYPE_R4:
1867                         case MONO_TYPE_R8:
1868                         case MONO_TYPE_VALUETYPE:
1869                                 /* MS seems to create the objects if a null is passed in */
1870                                 if (! ((gpointer *)params->vector)[i])
1871                                         ((gpointer*)params->vector)[i] = mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i]));
1872                                 pa [i] = (char *)(((gpointer *)params->vector)[i]) + sizeof (MonoObject);
1873                                 break;
1874                         case MONO_TYPE_STRING:
1875                         case MONO_TYPE_OBJECT:
1876                         case MONO_TYPE_CLASS:
1877                         case MONO_TYPE_ARRAY:
1878                         case MONO_TYPE_SZARRAY:
1879                                 if (sig->params [i]->byref)
1880                                         pa [i] = &(((gpointer *)params->vector)[i]);
1881                                 else
1882                                         pa [i] = (char *)(((gpointer *)params->vector)[i]);
1883                                 break;
1884                         default:
1885                                 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
1886                         }
1887                 }
1888         }
1889
1890         if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
1891                 void *o = obj;
1892                 if (!obj) {
1893                         obj = mono_object_new (mono_domain_get (), method->klass);
1894                         if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
1895                                 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
1896                         }
1897                         if (method->klass->valuetype)
1898                                 o = mono_object_unbox (obj);
1899                         else
1900                                 o = obj;
1901                 }
1902                 mono_runtime_invoke (method, o, pa, exc);
1903                 return obj;
1904         } else {
1905                 /* obj must be already unboxed if needed */
1906                 return mono_runtime_invoke (method, obj, pa, exc);
1907         }
1908 }
1909
1910 static void
1911 arith_overflow (void)
1912 {
1913         mono_raise_exception (mono_get_exception_overflow ());
1914 }
1915
1916 /**
1917  * mono_object_allocate:
1918  * @size: number of bytes to allocate
1919  *
1920  * This is a very simplistic routine until we have our GC-aware
1921  * memory allocator. 
1922  *
1923  * Returns: an allocated object of size @size, or NULL on failure.
1924  */
1925 static inline void *
1926 mono_object_allocate (size_t size)
1927 {
1928 #if HAVE_BOEHM_GC
1929         /* if this is changed to GC_debug_malloc(), we need to change also metadata/gc.c */
1930         void *o = GC_MALLOC (size);
1931 #else
1932         void *o = calloc (1, size);
1933         if (!o)
1934                 return mono_gc_out_of_memory (size);
1935 #endif
1936         mono_stats.new_object_count++;
1937
1938         return o;
1939 }
1940
1941 #if CREATION_SPEEDUP
1942 static inline void *
1943 mono_object_allocate_spec (size_t size, void *gcdescr)
1944 {
1945         /* if this is changed to GC_debug_malloc(), we need to change also metadata/gc.c */
1946         void *o = GC_GCJ_MALLOC (size, gcdescr);
1947         mono_stats.new_object_count++;
1948
1949         return o;
1950 }
1951 #endif
1952
1953 /**
1954  * mono_object_new:
1955  * @klass: the class of the object that we want to create
1956  *
1957  * Returns: a newly created object whose definition is
1958  * looked up using @klass.   This will not invoke any constructors, 
1959  * so the consumer of this routine has to invoke any constructors on
1960  * its own to initialize the object.
1961  */
1962 MonoObject *
1963 mono_object_new (MonoDomain *domain, MonoClass *klass)
1964 {
1965         MONO_ARCH_SAVE_REGS;
1966         return mono_object_new_specific (mono_class_vtable (domain, klass));
1967 }
1968
1969 /**
1970  * mono_object_new_specific:
1971  * @vtable: the vtable of the object that we want to create
1972  *
1973  * Returns: A newly created object with class and domain specified
1974  * by @vtable
1975  */
1976 MonoObject *
1977 mono_object_new_specific (MonoVTable *vtable)
1978 {
1979         MonoObject *o;
1980
1981         MONO_ARCH_SAVE_REGS;
1982         
1983         if (vtable->remote)
1984         {
1985                 gpointer pa [1];
1986                 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
1987
1988                 if (im == NULL) {
1989                         MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
1990                         int i;
1991
1992                         if (!klass->inited)
1993                                 mono_class_init (klass);
1994
1995                         for (i = 0; i < klass->method.count; ++i) {
1996                                 if (!strcmp ("CreateProxyForType", klass->methods [i]->name) &&
1997                                         klass->methods [i]->signature->param_count == 1) {
1998                                         im = klass->methods [i];
1999                                         break;
2000                                 }
2001                         }
2002                         g_assert (im);
2003                         vtable->domain->create_proxy_for_type_method = im;
2004                 }
2005         
2006                 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
2007
2008                 o = mono_runtime_invoke (im, NULL, pa, NULL);           
2009                 if (o != NULL) return o;
2010         }
2011
2012         return mono_object_new_alloc_specific (vtable);
2013 }
2014
2015 MonoObject *
2016 mono_object_new_alloc_specific (MonoVTable *vtable)
2017 {
2018         MonoObject *o;
2019
2020 #if CREATION_SPEEDUP
2021         if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2022                 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
2023         } else {
2024 /*              printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
2025                 o = mono_object_allocate (vtable->klass->instance_size);
2026                 o->vtable = vtable;
2027         }
2028 #else
2029         o = mono_object_allocate (vtable->klass->instance_size);
2030         o->vtable = vtable;
2031 #endif
2032         if (vtable->klass->has_finalize)
2033                 mono_object_register_finalizer (o);
2034         
2035         mono_profiler_allocation (o, vtable->klass);
2036         return o;
2037 }
2038
2039 #if CREATION_SPEEDUP
2040
2041 MonoObject*
2042 mono_object_new_fast (MonoVTable *vtable)
2043 {
2044         return GC_GCJ_MALLOC (vtable->klass->instance_size, vtable);
2045 }
2046
2047 #endif
2048
2049 /**
2050  * mono_class_get_allocation_ftn:
2051  * @vtable: vtable
2052  * @pass_size_in_words: 
2053  *
2054  * Return the allocation function appropriate for the given class.
2055  */
2056
2057 void*
2058 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean *pass_size_in_words)
2059 {
2060         *pass_size_in_words = FALSE;
2061
2062         if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
2063                 return mono_object_new_specific;
2064
2065 #if CREATION_SPEEDUP
2066         if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2067
2068                 return mono_object_new_fast;
2069
2070                 /* 
2071                  * FIXME: This is actually slower than mono_object_new_fast, because
2072                  * of the overhead of parameter passing.
2073                  */
2074                 /*
2075                 *pass_size_in_words = TRUE;
2076 #ifdef GC_REDIRECT_TO_LOCAL
2077                 return GC_local_gcj_fast_malloc;
2078 #else
2079                 return GC_gcj_fast_malloc;
2080 #endif
2081                 */
2082         }
2083 #endif
2084
2085         return mono_object_new_specific;
2086 }
2087
2088 /**
2089  * mono_object_new_from_token:
2090  * @image: Context where the type_token is hosted
2091  * @token: a token of the type that we want to create
2092  *
2093  * Returns: A newly created object whose definition is
2094  * looked up using @token in the @image image
2095  */
2096 MonoObject *
2097 mono_object_new_from_token  (MonoDomain *domain, MonoImage *image, guint32 token)
2098 {
2099         MonoClass *class;
2100
2101         class = mono_class_get (image, token);
2102
2103         return mono_object_new (domain, class);
2104 }
2105
2106
2107 /**
2108  * mono_object_clone:
2109  * @obj: the object to clone
2110  *
2111  * Returns: A newly created object who is a shallow copy of @obj
2112  */
2113 MonoObject *
2114 mono_object_clone (MonoObject *obj)
2115 {
2116         MonoObject *o;
2117         int size;
2118
2119         size = obj->vtable->klass->instance_size;
2120         o = mono_object_allocate (size);
2121         mono_profiler_allocation (o, obj->vtable->klass);
2122
2123         memcpy (o, obj, size);
2124
2125         if (obj->vtable->klass->has_finalize)
2126                 mono_object_register_finalizer (o);
2127         return o;
2128 }
2129
2130 /**
2131  * mono_array_full_copy:
2132  * @src: source array to copy
2133  * @dest: destination array
2134  *
2135  * Copies the content of one array to another with exactly the same type and size.
2136  */
2137 void
2138 mono_array_full_copy (MonoArray *src, MonoArray *dest)
2139 {
2140         int size;
2141         MonoClass *klass = src->obj.vtable->klass;
2142
2143         MONO_ARCH_SAVE_REGS;
2144
2145         g_assert (klass == dest->obj.vtable->klass);
2146
2147         size = mono_array_length (src);
2148         g_assert (size == mono_array_length (dest));
2149         size *= mono_array_element_size (klass);
2150         memcpy (&dest->vector, &src->vector, size);
2151 }
2152
2153 /**
2154  * mono_array_clone_in_domain:
2155  * @domain: the domain in which the array will be cloned into
2156  * @array: the array to clone
2157  *
2158  * This routine returns a copy of the array that is hosted on the
2159  * specified MonoDomain.
2160  */
2161 MonoArray*
2162 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
2163 {
2164         MonoArray *o;
2165         int size, i;
2166         guint32 *sizes;
2167         MonoClass *klass = array->obj.vtable->klass;
2168
2169         MONO_ARCH_SAVE_REGS;
2170
2171         if (array->bounds == NULL) {
2172                 size = mono_array_length (array);
2173                 o = mono_array_new_full (domain, klass, &size, NULL);
2174
2175                 size *= mono_array_element_size (klass);
2176                 memcpy (&o->vector, &array->vector, size);
2177                 return o;
2178         }
2179         
2180         sizes = alloca (klass->rank * sizeof(guint32) * 2);
2181         size = mono_array_element_size (klass);
2182         for (i = 0; i < klass->rank; ++i) {
2183                 sizes [i] = array->bounds [i].length;
2184                 size *= array->bounds [i].length;
2185                 sizes [i + klass->rank] = array->bounds [i].lower_bound;
2186         }
2187         o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
2188         memcpy (&o->vector, &array->vector, size);
2189
2190         return o;
2191 }
2192
2193 /**
2194  * mono_array_clone:
2195  * @array: the array to clone
2196  *
2197  * Returns: A newly created array who is a shallow copy of @array
2198  */
2199 MonoArray*
2200 mono_array_clone (MonoArray *array)
2201 {
2202         return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
2203 }
2204
2205 /* helper macros to check for overflow when calculating the size of arrays */
2206 #define MYGUINT32_MAX 4294967295U
2207 #define CHECK_ADD_OVERFLOW_UN(a,b) \
2208         (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
2209 #define CHECK_MUL_OVERFLOW_UN(a,b) \
2210         ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
2211         (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
2212
2213 /**
2214  * mono_array_new_full:
2215  * @domain: domain where the object is created
2216  * @array_class: array class
2217  * @lengths: lengths for each dimension in the array
2218  * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
2219  *
2220  * This routine creates a new array objects with the given dimensions,
2221  * lower bounds and type.
2222  */
2223 MonoArray*
2224 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, 
2225                      guint32 *lengths, guint32 *lower_bounds)
2226 {
2227         guint32 byte_len, len;
2228         MonoObject *o;
2229         MonoArray *array;
2230         MonoArrayBounds *bounds;
2231         MonoVTable *vtable;
2232         int i;
2233
2234         if (!array_class->inited)
2235                 mono_class_init (array_class);
2236
2237         byte_len = mono_array_element_size (array_class);
2238         len = 1;
2239
2240         if (array_class->rank == 1 &&
2241             (lower_bounds == NULL || lower_bounds [0] == 0)) {
2242                 bounds = NULL;
2243                 len = lengths [0];
2244                 if ((int) len < 0)
2245                         arith_overflow ();
2246         } else {
2247         #if HAVE_BOEHM_GC
2248                 bounds = GC_MALLOC (sizeof (MonoArrayBounds) * array_class->rank);
2249         #else
2250                 bounds = g_malloc0 (sizeof (MonoArrayBounds) * array_class->rank);
2251         #endif
2252                 for (i = 0; i < array_class->rank; ++i)
2253                         if ((int) lengths [i] < 0)
2254                                 arith_overflow ();
2255                 
2256                 for (i = 0; i < array_class->rank; ++i) {
2257                         bounds [i].length = lengths [i];
2258                         if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
2259                                 mono_gc_out_of_memory (MYGUINT32_MAX);
2260                         len *= lengths [i];
2261                 }
2262
2263                 if (lower_bounds)
2264                         for (i = 0; i < array_class->rank; ++i)
2265                                 bounds [i].lower_bound = lower_bounds [i];
2266         }
2267
2268         if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
2269                 mono_gc_out_of_memory (MYGUINT32_MAX);
2270         byte_len *= len;
2271         if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
2272                 mono_gc_out_of_memory (MYGUINT32_MAX);
2273         byte_len += sizeof (MonoArray);
2274         /* 
2275          * Following three lines almost taken from mono_object_new ():
2276          * they need to be kept in sync.
2277          */
2278         vtable = mono_class_vtable (domain, array_class);
2279 #if CREATION_SPEEDUP
2280         if (vtable->gc_descr != GC_NO_DESCRIPTOR)
2281                 o = mono_object_allocate_spec (byte_len, vtable);
2282         else {
2283                 o = mono_object_allocate (byte_len);
2284                 o->vtable = vtable;
2285         }
2286 #else
2287         o = mono_object_allocate (byte_len);
2288         o->vtable = vtable;
2289 #endif
2290
2291         array = (MonoArray*)o;
2292
2293         array->bounds = bounds;
2294         array->max_length = len;
2295
2296         mono_profiler_allocation (o, array_class);
2297
2298         return array;
2299 }
2300
2301 /**
2302  * mono_array_new:
2303  * @domain: domain where the object is created
2304  * @eclass: element class
2305  * @n: number of array elements
2306  *
2307  * This routine creates a new szarray with @n elements of type @eclass.
2308  */
2309 MonoArray *
2310 mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
2311 {
2312         MonoClass *ac;
2313
2314         MONO_ARCH_SAVE_REGS;
2315
2316         ac = mono_array_class_get (eclass, 1);
2317         g_assert (ac != NULL);
2318
2319         return mono_array_new_specific (mono_class_vtable (domain, ac), n);
2320 }
2321
2322 /**
2323  * mono_array_new_specific:
2324  * @vtable: a vtable in the appropriate domain for an initialized class
2325  * @n: number of array elements
2326  *
2327  * This routine is a fast alternative to mono_array_new() for code which
2328  * can be sure about the domain it operates in.
2329  */
2330 MonoArray *
2331 mono_array_new_specific (MonoVTable *vtable, guint32 n)
2332 {
2333         MonoObject *o;
2334         MonoArray *ao;
2335         guint32 byte_len, elem_size;
2336
2337         MONO_ARCH_SAVE_REGS;
2338
2339         if ((int) n < 0)
2340                 arith_overflow ();
2341         
2342         elem_size = mono_array_element_size (vtable->klass);
2343         if (CHECK_MUL_OVERFLOW_UN (n, elem_size))
2344                 mono_gc_out_of_memory (MYGUINT32_MAX);
2345         byte_len = n * elem_size;
2346         if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
2347                 mono_gc_out_of_memory (MYGUINT32_MAX);
2348         byte_len += sizeof (MonoArray);
2349 #if CREATION_SPEEDUP
2350         if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2351                 o = mono_object_allocate_spec (byte_len, vtable);
2352         } else {
2353 /*              printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
2354                 o = mono_object_allocate (byte_len);
2355                 o->vtable = vtable;
2356         }
2357 #else
2358         o = mono_object_allocate (byte_len);
2359         o->vtable = vtable;
2360 #endif
2361
2362         ao = (MonoArray *)o;
2363         ao->bounds = NULL;
2364         ao->max_length = n;
2365         mono_profiler_allocation (o, vtable->klass);
2366
2367         return ao;
2368 }
2369
2370 /**
2371  * mono_string_new_utf16:
2372  * @text: a pointer to an utf16 string
2373  * @len: the length of the string
2374  *
2375  * Returns: A newly created string object which contains @text.
2376  */
2377 MonoString *
2378 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
2379 {
2380         MonoString *s;
2381         
2382         s = mono_string_new_size (domain, len);
2383         g_assert (s != NULL);
2384
2385         memcpy (mono_string_chars (s), text, len * 2);
2386
2387         return s;
2388 }
2389
2390 /**
2391  * mono_string_new_size:
2392  * @text: a pointer to an utf16 string
2393  * @len: the length of the string
2394  *
2395  * Returns: A newly created string object of @len
2396  */
2397 MonoString *
2398 mono_string_new_size (MonoDomain *domain, gint32 len)
2399 {
2400         MonoString *s;
2401         MonoVTable *vtable;
2402         size_t size = (sizeof (MonoString) + ((len + 1) * 2));
2403
2404         /* overflow ? can't fit it, can't allocate it! */
2405         if (len > size)
2406                 mono_gc_out_of_memory (-1);
2407
2408         vtable = mono_class_vtable (domain, mono_defaults.string_class);
2409
2410 #if CREATION_SPEEDUP
2411         if (vtable->gc_descr != GC_NO_DESCRIPTOR)
2412                 s = mono_object_allocate_spec (size, vtable);
2413         else {
2414                 s = (MonoString*)mono_object_allocate (size);
2415                 s->object.vtable = vtable;
2416         }
2417 #else
2418         s = (MonoString*)mono_object_allocate (size);
2419         s->object.vtable = vtable;
2420 #endif
2421
2422         s->length = len;
2423         mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
2424
2425         return s;
2426 }
2427
2428 /**
2429  * mono_string_new_len:
2430  * @text: a pointer to an utf8 string
2431  * @length: number of bytes in @text to consider
2432  *
2433  * Returns: A newly created string object which contains @text.
2434  */
2435 MonoString*
2436 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
2437 {
2438         GError *error = NULL;
2439         MonoString *o = NULL;
2440         guint16 *ut;
2441         glong items_written;
2442
2443         ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
2444
2445         if (!error)
2446                 o = mono_string_new_utf16 (domain, ut, items_written);
2447         else 
2448                 g_error_free (error);
2449
2450         g_free (ut);
2451
2452         return o;
2453 }
2454
2455 /**
2456  * mono_string_new:
2457  * @text: a pointer to an utf8 string
2458  *
2459  * Returns: A newly created string object which contains @text.
2460  */
2461 MonoString*
2462 mono_string_new (MonoDomain *domain, const char *text)
2463 {
2464         GError *error = NULL;
2465         MonoString *o = NULL;
2466         guint16 *ut;
2467         glong items_written;
2468         int l;
2469
2470         l = strlen (text);
2471         
2472         ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
2473
2474         if (!error)
2475                 o = mono_string_new_utf16 (domain, ut, items_written);
2476         else 
2477                 g_error_free (error);
2478
2479         g_free (ut);
2480
2481         return o;
2482 }
2483
2484 /**
2485  * mono_string_new_wrapper:
2486  * @text: pointer to utf8 characters.
2487  *
2488  * Helper function to create a string object from @text in the current domain.
2489  */
2490 MonoString*
2491 mono_string_new_wrapper (const char *text)
2492 {
2493         MonoDomain *domain = mono_domain_get ();
2494
2495         MONO_ARCH_SAVE_REGS;
2496
2497         if (text)
2498                 return mono_string_new (domain, text);
2499
2500         return NULL;
2501 }
2502
2503 /**
2504  * mono_value_box:
2505  * @class: the class of the value
2506  * @value: a pointer to the unboxed data
2507  *
2508  * Returns: A newly created object which contains @value.
2509  */
2510 MonoObject *
2511 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
2512 {
2513         MonoObject *res;
2514         int size;
2515         MonoVTable *vtable;
2516
2517         g_assert (class->valuetype);
2518
2519         vtable = mono_class_vtable (domain, class);
2520         size = mono_class_instance_size (class);
2521         res = mono_object_allocate (size);
2522         res->vtable = vtable;
2523         mono_profiler_allocation (res, class);
2524
2525         size = size - sizeof (MonoObject);
2526
2527 #if NO_UNALIGNED_ACCESS
2528         memcpy ((char *)res + sizeof (MonoObject), value, size);
2529 #else
2530         switch (size) {
2531         case 1:
2532                 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
2533                 break;
2534         case 2:
2535                 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
2536                 break;
2537         case 4:
2538                 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
2539                 break;
2540         case 8:
2541                 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
2542                 break;
2543         default:
2544                 memcpy ((char *)res + sizeof (MonoObject), value, size);
2545         }
2546 #endif
2547         if (class->has_finalize)
2548                 mono_object_register_finalizer (res);
2549         return res;
2550 }
2551
2552 /**
2553  * mono_object_get_domain:
2554  * @obj: object to query
2555  * 
2556  * Returns: the MonoDomain where the object is hosted
2557  */
2558 MonoDomain*
2559 mono_object_get_domain (MonoObject *obj)
2560 {
2561         return mono_object_domain (obj);
2562 }
2563
2564 /**
2565  * mono_object_get_class:
2566  * @obj: object to query
2567  * 
2568  * Returns: the MonOClass of the object.
2569  */
2570 MonoClass*
2571 mono_object_get_class (MonoObject *obj)
2572 {
2573         return mono_object_class (obj);
2574 }
2575
2576 /**
2577  * mono_object_unbox:
2578  * @obj: object to unbox
2579  * 
2580  * Returns: a pointer to the start of the valuetype boxed in this
2581  * object.
2582  *
2583  * This method will assert if the object passed is not a valuetype.
2584  */
2585 gpointer
2586 mono_object_unbox (MonoObject *obj)
2587 {
2588         /* add assert for valuetypes? */
2589         g_assert (obj->vtable->klass->valuetype);
2590         return ((char*)obj) + sizeof (MonoObject);
2591 }
2592
2593 /**
2594  * mono_object_isinst:
2595  * @obj: an object
2596  * @klass: a pointer to a class 
2597  *
2598  * Returns: @obj if @obj is derived from @klass
2599  */
2600 MonoObject *
2601 mono_object_isinst (MonoObject *obj, MonoClass *klass)
2602 {
2603         if (!klass->inited)
2604                 mono_class_init (klass);
2605
2606         if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) 
2607                 return mono_object_isinst_mbyref (obj, klass);
2608
2609         if (!obj)
2610                 return NULL;
2611
2612         return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
2613 }
2614
2615 MonoObject *
2616 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
2617 {
2618         MonoVTable *vt;
2619
2620         if (!obj)
2621                 return NULL;
2622
2623         vt = obj->vtable;
2624         
2625         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2626                 if ((klass->interface_id <= vt->max_interface_id) &&
2627                     (vt->interface_offsets [klass->interface_id] != 0))
2628                         return obj;
2629         }
2630         else {
2631                 MonoClass *oklass = vt->klass;
2632                 if ((oklass == mono_defaults.transparent_proxy_class))
2633                         oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
2634         
2635                 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
2636                         return obj;
2637         }
2638
2639         if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info) 
2640         {
2641                 MonoDomain *domain = mono_domain_get ();
2642                 MonoObject *res;
2643                 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
2644                 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
2645                 MonoMethod *im = NULL;
2646                 gpointer pa [2];
2647                 int i;
2648         
2649                 for (i = 0; i < rpklass->method.count; ++i) {
2650                         if (!strcmp ("CanCastTo", rpklass->methods [i]->name)) {
2651                                 im = rpklass->methods [i];
2652                                 break;
2653                         }
2654                 }
2655         
2656                 im = mono_object_get_virtual_method (rp, im);
2657                 g_assert (im);
2658         
2659                 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
2660                 pa [1] = obj;
2661
2662                 res = mono_runtime_invoke (im, rp, pa, NULL);
2663         
2664                 if (*(MonoBoolean *) mono_object_unbox(res)) {
2665                         /* Update the vtable of the remote type, so it can safely cast to this new type */
2666                         mono_upgrade_remote_class (domain, ((MonoTransparentProxy *)obj)->remote_class, klass);
2667                         obj->vtable = mono_remote_class_vtable (domain, ((MonoTransparentProxy *)obj)->remote_class, (MonoRealProxy *)rp);
2668                         return obj;
2669                 }
2670         }
2671
2672         return NULL;
2673 }
2674
2675 /**
2676  * mono_object_castclass_mbyref:
2677  * @obj: an object
2678  * @klass: a pointer to a class 
2679  *
2680  * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
2681  */
2682 MonoObject *
2683 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
2684 {
2685         if (!obj) return NULL;
2686         if (mono_object_isinst_mbyref (obj, klass)) return obj;
2687                 
2688         mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
2689                                                         "System",
2690                                                         "InvalidCastException"));
2691         return NULL;
2692 }
2693
2694 typedef struct {
2695         MonoDomain *orig_domain;
2696         char *ins;
2697         MonoString *res;
2698 } LDStrInfo;
2699
2700 static void
2701 str_lookup (MonoDomain *domain, gpointer user_data)
2702 {
2703         LDStrInfo *info = user_data;
2704         if (info->res || domain == info->orig_domain)
2705                 return;
2706         mono_domain_lock (domain);
2707         info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
2708         mono_domain_unlock (domain);
2709 }
2710
2711 static MonoString*
2712 mono_string_is_interned_lookup (MonoString *str, int insert)
2713 {
2714         MonoGHashTable *ldstr_table;
2715         MonoString *res;
2716         MonoDomain *domain;
2717         char *ins = g_malloc (4 + str->length * 2);
2718         char *p;
2719         
2720         /* Encode the length */
2721         /* Same code as in mono_image_insert_string () */
2722         p = ins;
2723         mono_metadata_encode_value (1 | (2 * str->length), p, &p);
2724
2725         /*
2726          * ins is stored in the hash table as a key and needs to have the same
2727          * representation as in the metadata: we swap the character bytes on big
2728          * endian boxes.
2729          */
2730 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
2731         {
2732                 int i;
2733                 char *p2 = (char *)mono_string_chars (str);
2734                 for (i = 0; i < str->length; ++i) {
2735                         *p++ = p2 [1];
2736                         *p++ = p2 [0];
2737                         p2 += 2;
2738                 }
2739         }
2740 #else
2741         memcpy (p, mono_string_chars (str), str->length * 2);
2742 #endif
2743         domain = ((MonoObject *)str)->vtable->domain;
2744         ldstr_table = domain->ldstr_table;
2745         mono_domain_lock (domain);
2746         if ((res = mono_g_hash_table_lookup (ldstr_table, ins))) {
2747                 mono_domain_unlock (domain);
2748                 g_free (ins);
2749                 return res;
2750         }
2751         if (insert) {
2752                 mono_g_hash_table_insert (ldstr_table, ins, str);
2753                 mono_domain_unlock (domain);
2754                 return str;
2755         } else {
2756                 LDStrInfo ldstr_info;
2757                 ldstr_info.orig_domain = domain;
2758                 ldstr_info.ins = ins;
2759                 ldstr_info.res = NULL;
2760
2761                 mono_domain_foreach (str_lookup, &ldstr_info);
2762                 if (ldstr_info.res) {
2763                         /* 
2764                          * the string was already interned in some other domain:
2765                          * intern it in the current one as well.
2766                          */
2767                         mono_g_hash_table_insert (ldstr_table, ins, str);
2768                         mono_domain_unlock (domain);
2769                         return str;
2770                 }
2771         }
2772         mono_domain_unlock (domain);
2773         g_free (ins);
2774         return NULL;
2775 }
2776
2777 /**
2778  * mono_string_is_interned:
2779  * @o: String to probe
2780  *
2781  * Returns whether the string has been interned.
2782  */
2783 MonoString*
2784 mono_string_is_interned (MonoString *o)
2785 {
2786         return mono_string_is_interned_lookup (o, FALSE);
2787 }
2788
2789 /**
2790  * mono_string_interne:
2791  * @o: String to intern
2792  *
2793  * Interns the string passed.  
2794  * Returns: The interned string.
2795  */
2796 MonoString*
2797 mono_string_intern (MonoString *str)
2798 {
2799         return mono_string_is_interned_lookup (str, TRUE);
2800 }
2801
2802 /**
2803  * mono_ldstr:
2804  * @domain: the domain where the string will be used.
2805  * @image: a metadata context
2806  * @idx: index into the user string table.
2807  * 
2808  * Implementation for the ldstr opcode.
2809  * Returns: a loaded string from the @image/@idx combination.
2810  */
2811 MonoString*
2812 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
2813 {
2814         MONO_ARCH_SAVE_REGS;
2815
2816         if (image->dynamic)
2817                 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx);
2818         else
2819                 return mono_ldstr_metdata_sig (domain, mono_metadata_user_string (image, idx));
2820 }
2821
2822 /**
2823  * mono_ldstr_metdata_sig
2824  * @domain: the domain for the string
2825  * @sig: the signature of a metadata string
2826  *
2827  * Returns: a MonoString for a string stored in the metadata
2828  */
2829 static MonoString*
2830 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig)
2831 {
2832         const char *str = sig;
2833         MonoString *o;
2834         size_t len2;
2835         
2836         mono_domain_lock (domain);
2837         if ((o = mono_g_hash_table_lookup (domain->ldstr_table, sig))) {
2838                 mono_domain_unlock (domain);
2839                 return o;
2840         }
2841         
2842         len2 = mono_metadata_decode_blob_size (str, &str);
2843         len2 >>= 1;
2844
2845         o = mono_string_new_utf16 (domain, (guint16*)str, len2);
2846 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
2847         {
2848                 int i;
2849                 guint16 *p2 = (guint16*)mono_string_chars (o);
2850                 for (i = 0; i < len2; ++i) {
2851                         *p2 = GUINT16_FROM_LE (*p2);
2852                         ++p2;
2853                 }
2854         }
2855 #endif
2856         mono_g_hash_table_insert (domain->ldstr_table, (gpointer)sig, o);
2857         mono_domain_unlock (domain);
2858
2859         return o;
2860 }
2861
2862 /**
2863  * mono_string_to_utf8:
2864  * @s: a System.String
2865  *
2866  * Return the UTF8 representation for @s.
2867  * the resulting buffer nedds to be freed with g_free().
2868  */
2869 char *
2870 mono_string_to_utf8 (MonoString *s)
2871 {
2872         char *as;
2873         GError *error = NULL;
2874
2875         if (s == NULL)
2876                 return NULL;
2877
2878         if (!s->length)
2879                 return g_strdup ("");
2880
2881         as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, NULL, &error);
2882         if (error) {
2883                 g_warning (error->message);
2884                 g_error_free (error);
2885         }
2886
2887         return as;
2888 }
2889
2890 /**
2891  * mono_string_to_utf16:
2892  * @s: a MonoString
2893  *
2894  * Return an null-terminated array of the utf-16 chars
2895  * contained in @s. The result must be freed with g_free().
2896  * This is a temporary helper until our string implementation
2897  * is reworked to always include the null terminating char.
2898  */
2899 gunichar2 *
2900 mono_string_to_utf16 (MonoString *s)
2901 {
2902         char *as;
2903
2904         if (s == NULL)
2905                 return NULL;
2906
2907         as = g_malloc ((s->length * 2) + 2);
2908         as [(s->length * 2)] = '\0';
2909         as [(s->length * 2) + 1] = '\0';
2910
2911         if (!s->length) {
2912                 return (gunichar2 *)(as);
2913         }
2914         
2915         memcpy (as, mono_string_chars(s), s->length * 2);
2916         return (gunichar2 *)(as);
2917 }
2918
2919 /**
2920  * mono_string_from_utf16:
2921  * @data: the UTF16 string (LPWSTR) to convert
2922  *
2923  * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
2924  *
2925  * Returns: a MonoString.
2926  */
2927 MonoString *
2928 mono_string_from_utf16 (gunichar2 *data)
2929 {
2930         MonoDomain *domain = mono_domain_get ();
2931         int len = 0;
2932
2933         if (!data)
2934                 return NULL;
2935
2936         while (data [len]) len++;
2937
2938         return mono_string_new_utf16 (domain, data, len);
2939 }
2940
2941 static void
2942 default_ex_handler (MonoException *ex)
2943 {
2944         MonoObject *o = (MonoObject*)ex;
2945         g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
2946         exit (1);
2947 }
2948
2949 static MonoExceptionFunc ex_handler = default_ex_handler;
2950
2951 /**
2952  * mono_install_handler:
2953  * @func: exception handler
2954  *
2955  * This is an internal JIT routine used to install the handler for exceptions
2956  * being throwh.
2957  */
2958 void
2959 mono_install_handler (MonoExceptionFunc func)
2960 {
2961         ex_handler = func? func: default_ex_handler;
2962 }
2963
2964 /**
2965  * mono_raise_exception:
2966  * @ex: exception object
2967  *
2968  * Signal the runtime that the exception @ex has been raised in unmanaged code.
2969  */
2970 void
2971 mono_raise_exception (MonoException *ex) 
2972 {
2973         /*
2974          * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
2975          * that will cause gcc to omit the function epilog, causing problems when
2976          * the JIT tries to walk the stack, since the return address on the stack
2977          * will point into the next function in the executable, not this one.
2978          */
2979
2980         if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class)
2981                 mono_thread_current ()->abort_exc = ex;
2982         
2983         ex_handler (ex);
2984 }
2985
2986 /**
2987  * mono_wait_handle_new:
2988  * @domain: Domain where the object will be created
2989  * @handle: Handle for the wait handle
2990  *
2991  * Returns: A new MonoWaitHandle created in the given domain for the given handle
2992  */
2993 MonoWaitHandle *
2994 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
2995 {
2996         MonoWaitHandle *res;
2997
2998         res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
2999
3000         res->handle = handle;
3001
3002         return res;
3003 }
3004
3005 /**
3006  * mono_async_result_new:
3007  * @domain:domain where the object will be created.
3008  * @handle: wait handle.
3009  * @state: state to pass to AsyncResult
3010  * @data: C closure data.
3011  *
3012  * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
3013  * If the handle is not null, the handle is initialized to a MonOWaitHandle.
3014  *
3015  */
3016 MonoAsyncResult *
3017 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data)
3018 {
3019         MonoAsyncResult *res;
3020
3021         res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
3022
3023         res->data = data;
3024         res->async_state = state;
3025         if (handle != NULL)
3026                 res->handle = (MonoObject *) mono_wait_handle_new (domain, handle);
3027
3028         res->sync_completed = FALSE;
3029         res->completed = FALSE;
3030
3031         return res;
3032 }
3033
3034 void
3035 mono_message_init (MonoDomain *domain,
3036                    MonoMethodMessage *this, 
3037                    MonoReflectionMethod *method,
3038                    MonoArray *out_args)
3039 {
3040         MonoMethodSignature *sig = method->method->signature;
3041         MonoString *name;
3042         int i, j;
3043         char **names;
3044         guint8 arg_type;
3045
3046         this->method = method;
3047
3048         this->args = mono_array_new (domain, mono_defaults.object_class, sig->param_count);
3049         this->arg_types = mono_array_new (domain, mono_defaults.byte_class, sig->param_count);
3050         this->async_result = NULL;
3051         this->call_type = CallType_Sync;
3052
3053         names = g_new (char *, sig->param_count);
3054         mono_method_get_param_names (method->method, (const char **) names);
3055         this->names = mono_array_new (domain, mono_defaults.string_class, sig->param_count);
3056         
3057         for (i = 0; i < sig->param_count; i++) {
3058                  name = mono_string_new (domain, names [i]);
3059                  mono_array_set (this->names, gpointer, i, name);       
3060         }
3061
3062         g_free (names);
3063         for (i = 0, j = 0; i < sig->param_count; i++) {
3064
3065                 if (sig->params [i]->byref) {
3066                         if (out_args) {
3067                                 gpointer arg = mono_array_get (out_args, gpointer, j);
3068                                 mono_array_set (this->args, gpointer, i, arg);
3069                                 j++;
3070                         }
3071                         arg_type = 2;
3072                         if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
3073                                 arg_type |= 1;
3074                 } else {
3075                         arg_type = 1;
3076                 }
3077                 mono_array_set (this->arg_types, guint8, i, arg_type);
3078         }
3079 }
3080
3081 /**
3082  * mono_remoting_invoke:
3083  * @real_proxy: pointer to a RealProxy object
3084  * @msg: The MonoMethodMessage to execute
3085  * @exc: used to store exceptions
3086  * @out_args: used to store output arguments
3087  *
3088  * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
3089  * IMessage interface and it is not trivial to extract results from there. So
3090  * we call an helper method PrivateInvoke instead of calling
3091  * RealProxy::Invoke() directly.
3092  *
3093  * Returns: the result object.
3094  */
3095 MonoObject *
3096 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg, 
3097                       MonoObject **exc, MonoArray **out_args)
3098 {
3099         MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
3100         gpointer pa [4];
3101
3102         /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
3103
3104         if (!im) {
3105                 MonoClass *klass;
3106                 int i;
3107
3108                 klass = mono_defaults.real_proxy_class; 
3109                        
3110                 for (i = 0; i < klass->method.count; ++i) {
3111                         if (!strcmp ("PrivateInvoke", klass->methods [i]->name) &&
3112                             klass->methods [i]->signature->param_count == 4) {
3113                                 im = klass->methods [i];
3114                                 break;
3115                         }
3116                 }
3117         
3118                 g_assert (im);
3119                 real_proxy->vtable->domain->private_invoke_method = im;
3120         }
3121
3122         pa [0] = real_proxy;
3123         pa [1] = msg;
3124         pa [2] = exc;
3125         pa [3] = out_args;
3126
3127         return mono_runtime_invoke (im, NULL, pa, exc);
3128 }
3129
3130 MonoObject *
3131 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg, 
3132                      MonoObject **exc, MonoArray **out_args) 
3133 {
3134         MonoDomain *domain; 
3135         MonoMethod *method;
3136         MonoMethodSignature *sig;
3137         MonoObject *ret;
3138         int i, j, outarg_count = 0;
3139
3140         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
3141
3142                 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
3143                 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3144                         target = tp->rp->unwrapped_server;
3145                 } else {
3146                         return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
3147                 }
3148         }
3149
3150         domain = mono_domain_get (); 
3151         method = msg->method->method;
3152         sig = method->signature;
3153
3154         for (i = 0; i < sig->param_count; i++) {
3155                 if (sig->params [i]->byref) 
3156                         outarg_count++;
3157         }
3158
3159         *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
3160         *exc = NULL;
3161
3162         ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
3163
3164         for (i = 0, j = 0; i < sig->param_count; i++) {
3165                 if (sig->params [i]->byref) {
3166                         gpointer arg;
3167                         arg = mono_array_get (msg->args, gpointer, i);
3168                         mono_array_set (*out_args, gpointer, j, arg);
3169                         j++;
3170                 }
3171         }
3172
3173         return ret;
3174 }
3175
3176 /**
3177  * mono_print_unhandled_exception:
3178  * @exc: The exception
3179  *
3180  * Prints the unhandled exception.
3181  */
3182 void
3183 mono_print_unhandled_exception (MonoObject *exc)
3184 {
3185         char *message = (char *) "";
3186         MonoString *str; 
3187         MonoMethod *method;
3188         MonoClass *klass;
3189         gboolean free_message = FALSE;
3190         gint i;
3191
3192         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
3193                 klass = exc->vtable->klass;
3194                 method = NULL;
3195                 while (klass && method == NULL) {
3196                         for (i = 0; i < klass->method.count; ++i) {
3197                                 method = klass->methods [i];
3198                                 if (!strcmp ("ToString", method->name) &&
3199                                     method->signature->param_count == 0 &&
3200                                     method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
3201                                     method->flags & METHOD_ATTRIBUTE_PUBLIC) {
3202                                         break;
3203                                 }
3204                                 method = NULL;
3205                         }
3206                         
3207                         if (method == NULL)
3208                                 klass = klass->parent;
3209                 }
3210
3211                 g_assert (method);
3212
3213                 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
3214                 if (str) {
3215                         message = mono_string_to_utf8 (str);
3216                         free_message = TRUE;
3217                 }
3218         }                               
3219
3220         /*
3221          * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space, 
3222          *         exc->vtable->klass->name, message);
3223          */
3224         g_printerr ("\nUnhandled Exception: %s\n", message);
3225         
3226         if (free_message)
3227                 g_free (message);
3228 }
3229
3230 /**
3231  * mono_delegate_ctor:
3232  * @this: pointer to an uninitialized delegate object
3233  * @target: target object
3234  * @addr: pointer to native code
3235  *
3236  * This is used to initialize a delegate. We also insert the method_info if
3237  * we find the info with mono_jit_info_table_find().
3238  */
3239 void
3240 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
3241 {
3242         MonoDomain *domain = mono_domain_get ();
3243         MonoDelegate *delegate = (MonoDelegate *)this;
3244         MonoMethod *method = NULL;
3245         MonoClass *class;
3246         MonoJitInfo *ji;
3247
3248         g_assert (this);
3249         g_assert (addr);
3250
3251         class = this->vtable->klass;
3252
3253         if ((ji = mono_jit_info_table_find (domain, addr))) {
3254                 method = ji->method;
3255                 delegate->method_info = mono_method_get_object (domain, method, NULL);
3256         }
3257
3258         if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
3259                 g_assert (method);
3260                 method = mono_marshal_get_remoting_invoke (method);
3261                 delegate->method_ptr = mono_compile_method (method);
3262                 delegate->target = target;
3263         } else if (method->signature->hasthis && method->klass->valuetype) {
3264                 method = mono_marshal_get_unbox_wrapper (method);
3265                 delegate->method_ptr = mono_compile_method (method);
3266                 delegate->target = target;
3267         } else {
3268                 delegate->method_ptr = addr;
3269                 delegate->target = target;
3270         }
3271 }
3272
3273 /**
3274  * mono_method_call_message_new:
3275  * @method: method to encapsulate
3276  * @params: parameters to the method
3277  * @invoke: optional, delegate invoke.
3278  * @cb: async callback delegate.
3279  * @state: state passed to the async callback.
3280  *
3281  * Translates arguments pointers into a MonoMethodMessage.
3282  */
3283 MonoMethodMessage *
3284 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke, 
3285                               MonoDelegate **cb, MonoObject **state)
3286 {
3287         MonoDomain *domain = mono_domain_get ();
3288         MonoMethodSignature *sig = method->signature;
3289         MonoMethodMessage *msg;
3290         int i, count, type;
3291
3292         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class); 
3293         
3294         if (invoke) {
3295                 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
3296                 count =  sig->param_count - 2;
3297         } else {
3298                 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
3299                 count =  sig->param_count;
3300         }
3301
3302         for (i = 0; i < count; i++) {
3303                 gpointer vpos;
3304                 MonoClass *class;
3305                 MonoObject *arg;
3306
3307                 if (sig->params [i]->byref)
3308                         vpos = *((gpointer *)params [i]);
3309                 else 
3310                         vpos = params [i];
3311
3312                 type = sig->params [i]->type;
3313                 class = mono_class_from_mono_type (sig->params [i]);
3314
3315                 if (class->valuetype)
3316                         arg = mono_value_box (domain, class, vpos);
3317                 else 
3318                         arg = *((MonoObject **)vpos);
3319                       
3320                 mono_array_set (msg->args, gpointer, i, arg);
3321         }
3322
3323         if (cb != NULL && state != NULL) {
3324                 *cb = *((MonoDelegate **)params [i]);
3325                 i++;
3326                 *state = *((MonoObject **)params [i]);
3327         }
3328
3329         return msg;
3330 }
3331
3332 /**
3333  * mono_method_return_message_restore:
3334  *
3335  * Restore results from message based processing back to arguments pointers
3336  */
3337 void
3338 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
3339 {
3340         MonoMethodSignature *sig = method->signature;
3341         int i, j, type, size;
3342         for (i = 0, j = 0; i < sig->param_count; i++) {
3343                 MonoType *pt = sig->params [i];
3344
3345                 if (pt->byref) {
3346                         char *arg = mono_array_get (out_args, gpointer, j);
3347                         type = pt->type;
3348
3349                         switch (type) {
3350                         case MONO_TYPE_VOID:
3351                                 g_assert_not_reached ();
3352                                 break;
3353                         case MONO_TYPE_U1:
3354                         case MONO_TYPE_I1:
3355                         case MONO_TYPE_BOOLEAN:
3356                         case MONO_TYPE_U2:
3357                         case MONO_TYPE_I2:
3358                         case MONO_TYPE_CHAR:
3359                         case MONO_TYPE_U4:
3360                         case MONO_TYPE_I4:
3361                         case MONO_TYPE_I8:
3362                         case MONO_TYPE_U8:
3363                         case MONO_TYPE_R4:
3364                         case MONO_TYPE_R8:
3365                         case MONO_TYPE_VALUETYPE: {
3366                                 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
3367                                 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size); 
3368                                 break;
3369                         }
3370                         case MONO_TYPE_STRING:
3371                         case MONO_TYPE_CLASS: 
3372                         case MONO_TYPE_ARRAY:
3373                         case MONO_TYPE_SZARRAY:
3374                         case MONO_TYPE_OBJECT:
3375                                 **((MonoObject ***)params [i]) = (MonoObject *)arg;
3376                                 break;
3377                         default:
3378                                 g_assert_not_reached ();
3379                         }
3380
3381                         j++;
3382                 }
3383         }
3384 }
3385
3386 /**
3387  * mono_load_remote_field:
3388  * @this: pointer to an object
3389  * @klass: klass of the object containing @field
3390  * @field: the field to load
3391  * @res: a storage to store the result
3392  *
3393  * This method is called by the runtime on attempts to load fields of
3394  * transparent proxy objects. @this points to such TP, @klass is the class of
3395  * the object containing @field. @res is a storage location which can be
3396  * used to store the result.
3397  *
3398  * Returns: an address pointing to the value of field.
3399  */
3400 gpointer
3401 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
3402 {
3403         static MonoMethod *getter = NULL;
3404         MonoDomain *domain = mono_domain_get ();
3405         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3406         MonoClass *field_class;
3407         MonoMethodMessage *msg;
3408         MonoArray *out_args;
3409         MonoObject *exc;
3410         gpointer tmp;
3411
3412         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3413
3414         if (!res)
3415                 res = &tmp;
3416
3417         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3418                 mono_field_get_value (tp->rp->unwrapped_server, field, res);
3419                 return res;
3420         }
3421         
3422         if (!getter) {
3423                 int i;
3424
3425                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
3426                         MonoMethod *cm = mono_defaults.object_class->methods [i];
3427                
3428                         if (!strcmp (cm->name, "FieldGetter")) {
3429                                 getter = cm;
3430                                 break;
3431                         }
3432                 }
3433                 g_assert (getter);
3434         }
3435         
3436         field_class = mono_class_from_mono_type (field->type);
3437
3438         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3439         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
3440         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
3441
3442         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3443         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3444
3445         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3446
3447         if (exc) mono_raise_exception ((MonoException *)exc);
3448
3449         *res = mono_array_get (out_args, MonoObject *, 0);
3450
3451         if (field_class->valuetype) {
3452                 return ((char *)*res) + sizeof (MonoObject);
3453         } else
3454                 return res;
3455 }
3456
3457 /**
3458  * mono_load_remote_field_new:
3459  * @this: 
3460  * @klass: 
3461  * @field:
3462  *
3463  * Missing documentation.
3464  */
3465 MonoObject *
3466 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
3467 {
3468         static MonoMethod *getter = NULL;
3469         MonoDomain *domain = mono_domain_get ();
3470         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3471         MonoClass *field_class;
3472         MonoMethodMessage *msg;
3473         MonoArray *out_args;
3474         MonoObject *exc, *res;
3475
3476         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3477
3478         field_class = mono_class_from_mono_type (field->type);
3479
3480         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3481                 gpointer val;
3482                 if (field_class->valuetype) {
3483                         res = mono_object_new (domain, field_class);
3484                         val = ((gchar *) res) + sizeof (MonoObject);
3485                 } else {
3486                         val = &res;
3487                 }
3488                 mono_field_get_value (tp->rp->unwrapped_server, field, val);
3489                 return res;
3490         }
3491
3492         if (!getter) {
3493                 int i;
3494
3495                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
3496                         MonoMethod *cm = mono_defaults.object_class->methods [i];
3497                
3498                         if (!strcmp (cm->name, "FieldGetter")) {
3499                                 getter = cm;
3500                                 break;
3501                         }
3502                 }
3503                 g_assert (getter);
3504         }
3505         
3506         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3507         out_args = mono_array_new (domain, mono_defaults.object_class, 1);
3508         mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
3509
3510         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3511         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3512
3513         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3514
3515         if (exc) mono_raise_exception ((MonoException *)exc);
3516
3517         res = mono_array_get (out_args, MonoObject *, 0);
3518
3519         return res;
3520 }
3521
3522 /**
3523  * mono_store_remote_field:
3524  * @this: pointer to an object
3525  * @klass: klass of the object containing @field
3526  * @field: the field to load
3527  * @val: the value/object to store
3528  *
3529  * This method is called by the runtime on attempts to store fields of
3530  * transparent proxy objects. @this points to such TP, @klass is the class of
3531  * the object containing @field. @val is the new value to store in @field.
3532  */
3533 void
3534 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
3535 {
3536         static MonoMethod *setter = NULL;
3537         MonoDomain *domain = mono_domain_get ();
3538         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3539         MonoClass *field_class;
3540         MonoMethodMessage *msg;
3541         MonoArray *out_args;
3542         MonoObject *exc;
3543         MonoObject *arg;
3544
3545         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3546
3547         field_class = mono_class_from_mono_type (field->type);
3548
3549         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3550                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
3551                 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
3552                 return;
3553         }
3554
3555         if (!setter) {
3556                 int i;
3557
3558                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
3559                         MonoMethod *cm = mono_defaults.object_class->methods [i];
3560                
3561                         if (!strcmp (cm->name, "FieldSetter")) {
3562                                 setter = cm;
3563                                 break;
3564                         }
3565                 }
3566                 g_assert (setter);
3567         }
3568
3569         if (field_class->valuetype)
3570                 arg = mono_value_box (domain, field_class, val);
3571         else 
3572                 arg = *((MonoObject **)val);
3573                 
3574
3575         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3576         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
3577
3578         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3579         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3580         mono_array_set (msg->args, gpointer, 2, arg);
3581
3582         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3583
3584         if (exc) mono_raise_exception ((MonoException *)exc);
3585 }
3586
3587 /**
3588  * mono_store_remote_field_new:
3589  * @this:
3590  * @klass:
3591  * @field:
3592  * @arg:
3593  *
3594  * Missing documentation
3595  */
3596 void
3597 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
3598 {
3599         static MonoMethod *setter = NULL;
3600         MonoDomain *domain = mono_domain_get ();
3601         MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
3602         MonoClass *field_class;
3603         MonoMethodMessage *msg;
3604         MonoArray *out_args;
3605         MonoObject *exc;
3606
3607         g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
3608
3609         field_class = mono_class_from_mono_type (field->type);
3610
3611         if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
3612                 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
3613                 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
3614                 return;
3615         }
3616
3617         if (!setter) {
3618                 int i;
3619
3620                 for (i = 0; i < mono_defaults.object_class->method.count; ++i) {
3621                         MonoMethod *cm = mono_defaults.object_class->methods [i];
3622                
3623                         if (!strcmp (cm->name, "FieldSetter")) {
3624                                 setter = cm;
3625                                 break;
3626                         }
3627                 }
3628                 g_assert (setter);
3629         }
3630
3631         msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
3632         mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
3633
3634         mono_array_set (msg->args, gpointer, 0, mono_string_new (domain, klass->name));
3635         mono_array_set (msg->args, gpointer, 1, mono_string_new (domain, field->name));
3636         mono_array_set (msg->args, gpointer, 2, arg);
3637
3638         mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
3639
3640         if (exc) mono_raise_exception ((MonoException *)exc);
3641 }
3642