2007-04-06 Andreas Faerber <andreas.faerber@web.de>
[mono.git] / mono / metadata / object.c
blob30d3059882003d455a157ec6adde2b4de045d58d
1 /*
2 * object.c: Object creation for the Mono runtime
4 * Author:
5 * Miguel de Icaza (miguel@ximian.com)
6 * Paolo Molaro (lupus@ximian.com)
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/metadata/security-manager.h"
35 #include "mono/metadata/mono-debug-debugger.h"
36 #include <mono/os/gc_wrapper.h>
37 #include <mono/utils/strenc.h>
39 #ifdef HAVE_BOEHM_GC
40 #define NEED_TO_ZERO_PTRFREE 1
41 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = GC_MALLOC_ATOMIC ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
42 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = GC_MALLOC ((size)); (obj)->vtable = (vt);} while (0)
43 #ifdef HAVE_GC_GCJ_MALLOC
44 #define CREATION_SPEEDUP 1
45 #define GC_NO_DESCRIPTOR ((gpointer)(0 | GC_DS_LENGTH))
46 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_GCJ_MALLOC ((size),(type)); } while (0)
47 #define MAKE_STRING_DESCRIPTOR(bitmap,sz) GC_make_descriptor((GC_bitmap)(bitmap),(sz))
48 #define MAKE_DESCRIPTOR(bitmap,sz,objsize) GC_make_descriptor((GC_bitmap)(bitmap),(sz))
49 #else
50 #define GC_NO_DESCRIPTOR (NULL)
51 #define ALLOC_TYPED(dest,size,type) do { (dest) = GC_MALLOC ((size)); *(gpointer*)dest = (type);} while (0)
52 #define MAKE_STRING_DESCRIPTOR(bitmap,sz) NULL
53 #define MAKE_DESCRIPTOR(bitmap,sz,objsize) NULL
54 #endif
55 #else
56 #ifdef HAVE_SGEN_GC
57 #define GC_NO_DESCRIPTOR (NULL)
58 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
59 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = mono_gc_alloc_obj (vt, size);} while (0)
60 #define ALLOC_TYPED(dest,size,type) do { (dest) = mono_gc_alloc_obj (type, size);} while (0)
61 #define MAKE_STRING_DESCRIPTOR(bitmap,sz) mono_gc_make_descr_for_string ()
62 #define MAKE_DESCRIPTOR(bitmap,sz,objsize) mono_gc_make_descr_for_object ((bitmap), (sz), (objsize))
63 #else
64 #define NEED_TO_ZERO_PTRFREE 1
65 #define GC_NO_DESCRIPTOR (NULL)
66 #define ALLOC_PTRFREE(obj,vt,size) do { (obj) = malloc ((size)); (obj)->vtable = (vt); (obj)->synchronisation = NULL;} while (0)
67 #define ALLOC_OBJECT(obj,vt,size) do { (obj) = calloc (1, (size)); (obj)->vtable = (vt);} while (0)
68 #define ALLOC_TYPED(dest,size,type) do { (dest) = calloc (1, (size)); *(gpointer*)dest = (type);} while (0)
69 #define MAKE_STRING_DESCRIPTOR(bitmap,sz) NULL
70 #define MAKE_DESCRIPTOR(bitmap,sz,objsize) NULL
71 #endif
72 #endif
74 static MonoObject* mono_object_new_ptrfree (MonoVTable *vtable);
75 static MonoObject* mono_object_new_ptrfree_box (MonoVTable *vtable);
77 static void
78 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value);
80 static MonoString*
81 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig);
83 #define ldstr_lock() EnterCriticalSection (&ldstr_section)
84 #define ldstr_unlock() LeaveCriticalSection (&ldstr_section)
85 static CRITICAL_SECTION ldstr_section;
87 void
88 mono_runtime_object_init (MonoObject *this)
90 MonoMethod *method = NULL;
91 MonoClass *klass = this->vtable->klass;
93 method = mono_class_get_method_from_name (klass, ".ctor", 0);
94 g_assert (method);
96 if (method->klass->valuetype)
97 this = mono_object_unbox (this);
98 mono_runtime_invoke (method, this, NULL, NULL);
101 /* The pseudo algorithm for type initialization from the spec
102 Note it doesn't say anything about domains - only threads.
104 2. If the type is initialized you are done.
105 2.1. If the type is not yet initialized, try to take an
106 initialization lock.
107 2.2. If successful, record this thread as responsible for
108 initializing the type and proceed to step 2.3.
109 2.2.1. If not, see whether this thread or any thread
110 waiting for this thread to complete already holds the lock.
111 2.2.2. If so, return since blocking would create a deadlock. This thread
112 will now see an incompletely initialized state for the type,
113 but no deadlock will arise.
114 2.2.3 If not, block until the type is initialized then return.
115 2.3 Initialize the parent type and then all interfaces implemented
116 by this type.
117 2.4 Execute the type initialization code for this type.
118 2.5 Mark the type as initialized, release the initialization lock,
119 awaken any threads waiting for this type to be initialized,
120 and return.
124 typedef struct
126 guint32 initializing_tid;
127 guint32 waiting_count;
128 gboolean done;
129 CRITICAL_SECTION initialization_section;
130 } TypeInitializationLock;
132 /* for locking access to type_initialization_hash and blocked_thread_hash */
133 #define mono_type_initialization_lock() EnterCriticalSection (&type_initialization_section)
134 #define mono_type_initialization_unlock() LeaveCriticalSection (&type_initialization_section)
135 static CRITICAL_SECTION type_initialization_section;
137 /* from vtable to lock */
138 static GHashTable *type_initialization_hash;
140 /* from thread id to thread id being waited on */
141 static GHashTable *blocked_thread_hash;
143 /* Main thread */
144 static MonoThread *main_thread;
147 * mono_thread_set_main:
148 * @thread: thread to set as the main thread
150 * This function can be used to instruct the runtime to treat @thread
151 * as the main thread, ie, the thread that would normally execute the Main()
152 * method. This basically means that at the end of @thread, the runtime will
153 * wait for the existing foreground threads to quit and other such details.
155 void
156 mono_thread_set_main (MonoThread *thread)
158 main_thread = thread;
161 MonoThread*
162 mono_thread_get_main (void)
164 return main_thread;
167 void
168 mono_type_initialization_init (void)
170 InitializeCriticalSection (&type_initialization_section);
171 type_initialization_hash = g_hash_table_new (NULL, NULL);
172 blocked_thread_hash = g_hash_table_new (NULL, NULL);
173 InitializeCriticalSection (&ldstr_section);
176 void
177 mono_type_initialization_cleanup (void)
179 #if 0
180 /* This is causing race conditions with
181 * mono_release_type_locks
183 DeleteCriticalSection (&type_initialization_section);
184 #endif
185 DeleteCriticalSection (&ldstr_section);
189 * get_type_init_exception_for_vtable:
191 * Return the stored type initialization exception for VTABLE.
193 static MonoException*
194 get_type_init_exception_for_vtable (MonoVTable *vtable)
196 MonoDomain *domain = vtable->domain;
197 MonoClass *klass = vtable->klass;
198 MonoException *ex;
199 gchar *full_name;
201 g_assert (vtable->init_failed);
204 * If the initializing thread was rudely aborted, the exception is not stored
205 * in the hash.
207 ex = NULL;
208 mono_domain_lock (domain);
209 if (domain->type_init_exception_hash)
210 ex = mono_g_hash_table_lookup (domain->type_init_exception_hash, klass);
211 mono_domain_unlock (domain);
213 if (!ex) {
214 if (klass->name_space && *klass->name_space)
215 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
216 else
217 full_name = g_strdup (klass->name);
218 ex = mono_get_exception_type_initialization (full_name, NULL);
219 g_free (full_name);
222 return ex;
226 * mono_runtime_class_init:
227 * @vtable: vtable that needs to be initialized
229 * This routine calls the class constructor for @vtable.
231 void
232 mono_runtime_class_init (MonoVTable *vtable)
234 MonoException *exc;
235 MonoException *exc_to_throw;
236 MonoMethod *method = NULL;
237 MonoClass *klass;
238 gchar *full_name;
240 MONO_ARCH_SAVE_REGS;
242 if (vtable->initialized)
243 return;
245 exc = NULL;
246 klass = vtable->klass;
248 if (!klass->image->checked_module_cctor) {
249 mono_image_check_for_module_cctor (klass->image);
250 if (klass->image->has_module_cctor) {
251 MonoClass *module_klass = mono_class_get (klass->image, MONO_TOKEN_TYPE_DEF | 1);
252 mono_runtime_class_init (mono_class_vtable (vtable->domain, module_klass));
255 method = mono_class_get_cctor (klass);
257 if (method) {
258 MonoDomain *domain = vtable->domain;
259 TypeInitializationLock *lock;
260 guint32 tid = GetCurrentThreadId();
261 int do_initialization = 0;
262 MonoDomain *last_domain = NULL;
264 mono_type_initialization_lock ();
265 /* double check... */
266 if (vtable->initialized) {
267 mono_type_initialization_unlock ();
268 return;
270 if (vtable->init_failed) {
271 mono_type_initialization_unlock ();
273 /* The type initialization already failed once, rethrow the same exception */
274 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
275 return;
277 lock = g_hash_table_lookup (type_initialization_hash, vtable);
278 if (lock == NULL) {
279 /* This thread will get to do the initialization */
280 if (mono_domain_get () != domain) {
281 /* Transfer into the target domain */
282 last_domain = mono_domain_get ();
283 if (!mono_domain_set (domain, FALSE)) {
284 vtable->initialized = 1;
285 mono_type_initialization_unlock ();
286 mono_raise_exception (mono_get_exception_appdomain_unloaded ());
289 lock = g_malloc (sizeof(TypeInitializationLock));
290 InitializeCriticalSection (&lock->initialization_section);
291 lock->initializing_tid = tid;
292 lock->waiting_count = 1;
293 lock->done = FALSE;
294 /* grab the vtable lock while this thread still owns type_initialization_section */
295 EnterCriticalSection (&lock->initialization_section);
296 g_hash_table_insert (type_initialization_hash, vtable, lock);
297 do_initialization = 1;
298 } else {
299 gpointer blocked;
300 TypeInitializationLock *pending_lock;
302 if (lock->initializing_tid == tid || lock->done) {
303 mono_type_initialization_unlock ();
304 return;
306 /* see if the thread doing the initialization is already blocked on this thread */
307 blocked = GUINT_TO_POINTER (lock->initializing_tid);
308 while ((pending_lock = (TypeInitializationLock*) g_hash_table_lookup (blocked_thread_hash, blocked))) {
309 if (pending_lock->initializing_tid == tid) {
310 if (!pending_lock->done) {
311 mono_type_initialization_unlock ();
312 return;
313 } else {
314 /* the thread doing the initialization is blocked on this thread,
315 but on a lock that has already been freed. It just hasn't got
316 time to awake */
317 break;
320 blocked = GUINT_TO_POINTER (pending_lock->initializing_tid);
322 ++lock->waiting_count;
323 /* record the fact that we are waiting on the initializing thread */
324 g_hash_table_insert (blocked_thread_hash, GUINT_TO_POINTER (tid), lock);
326 mono_type_initialization_unlock ();
328 if (do_initialization) {
329 mono_runtime_invoke (method, NULL, NULL, (MonoObject **) &exc);
331 /* If the initialization failed, mark the class as unusable. */
332 /* Avoid infinite loops */
333 if (!(exc == NULL ||
334 (klass->image == mono_defaults.corlib &&
335 !strcmp (klass->name_space, "System") &&
336 !strcmp (klass->name, "TypeInitializationException")))) {
337 vtable->init_failed = 1;
339 if (klass->name_space && *klass->name_space)
340 full_name = g_strdup_printf ("%s.%s", klass->name_space, klass->name);
341 else
342 full_name = g_strdup (klass->name);
343 exc_to_throw = mono_get_exception_type_initialization (full_name, exc);
344 g_free (full_name);
347 * Store the exception object so it could be thrown on subsequent
348 * accesses.
350 mono_domain_lock (domain);
351 if (!domain->type_init_exception_hash)
352 domain->type_init_exception_hash = mono_g_hash_table_new_type (mono_aligned_addr_hash, NULL, MONO_HASH_VALUE_GC);
353 mono_g_hash_table_insert (domain->type_init_exception_hash, klass, exc_to_throw);
354 mono_domain_unlock (domain);
357 if (last_domain)
358 mono_domain_set (last_domain, TRUE);
359 lock->done = TRUE;
360 LeaveCriticalSection (&lock->initialization_section);
361 } else {
362 /* this just blocks until the initializing thread is done */
363 EnterCriticalSection (&lock->initialization_section);
364 LeaveCriticalSection (&lock->initialization_section);
367 mono_type_initialization_lock ();
368 if (lock->initializing_tid != tid)
369 g_hash_table_remove (blocked_thread_hash, GUINT_TO_POINTER (tid));
370 --lock->waiting_count;
371 if (lock->waiting_count == 0) {
372 DeleteCriticalSection (&lock->initialization_section);
373 g_hash_table_remove (type_initialization_hash, vtable);
374 g_free (lock);
376 if (!vtable->init_failed)
377 vtable->initialized = 1;
378 mono_type_initialization_unlock ();
380 if (vtable->init_failed) {
381 /* Either we were the initializing thread or we waited for the initialization */
382 mono_raise_exception (get_type_init_exception_for_vtable (vtable));
384 } else {
385 vtable->initialized = 1;
386 return;
390 static
391 gboolean release_type_locks (gpointer key, gpointer value, gpointer user)
393 MonoVTable *vtable = (MonoVTable*)key;
395 TypeInitializationLock *lock = (TypeInitializationLock*) value;
396 if (lock->initializing_tid == GPOINTER_TO_UINT (user) && !lock->done) {
397 lock->done = TRUE;
399 * Have to set this since it cannot be set by the normal code in
400 * mono_runtime_class_init (). In this case, the exception object is not stored,
401 * and get_type_init_exception_for_class () needs to be aware of this.
403 vtable->init_failed = 1;
404 LeaveCriticalSection (&lock->initialization_section);
405 --lock->waiting_count;
406 if (lock->waiting_count == 0) {
407 DeleteCriticalSection (&lock->initialization_section);
408 g_free (lock);
409 return TRUE;
412 return FALSE;
415 void
416 mono_release_type_locks (MonoThread *thread)
418 mono_type_initialization_lock ();
419 g_hash_table_foreach_remove (type_initialization_hash, release_type_locks, (gpointer)(gsize)(thread->tid));
420 mono_type_initialization_unlock ();
423 static gpointer
424 default_trampoline (MonoMethod *method)
426 return method;
429 static gpointer
430 default_remoting_trampoline (MonoMethod *method, MonoRemotingTarget target)
432 g_error ("remoting not installed");
433 return NULL;
436 static gpointer
437 default_delegate_trampoline (MonoMethod *method, gpointer addr)
439 g_assert_not_reached ();
440 return NULL;
443 static MonoTrampoline arch_create_jit_trampoline = default_trampoline;
444 static MonoRemotingTrampoline arch_create_remoting_trampoline = default_remoting_trampoline;
445 static MonoDelegateTrampoline arch_create_delegate_trampoline = default_delegate_trampoline;
447 void
448 mono_install_trampoline (MonoTrampoline func)
450 arch_create_jit_trampoline = func? func: default_trampoline;
453 void
454 mono_install_remoting_trampoline (MonoRemotingTrampoline func)
456 arch_create_remoting_trampoline = func? func: default_remoting_trampoline;
459 void
460 mono_install_delegate_trampoline (MonoDelegateTrampoline func)
462 arch_create_delegate_trampoline = func? func: default_delegate_trampoline;
465 static MonoCompileFunc default_mono_compile_method = NULL;
468 * mono_install_compile_method:
469 * @func: function to install
471 * This is a VM internal routine
473 void
474 mono_install_compile_method (MonoCompileFunc func)
476 default_mono_compile_method = func;
480 * mono_compile_method:
481 * @method: The method to compile.
483 * This JIT-compiles the method, and returns the pointer to the native code
484 * produced.
486 gpointer
487 mono_compile_method (MonoMethod *method)
489 if (!default_mono_compile_method) {
490 g_error ("compile method called on uninitialized runtime");
491 return NULL;
493 return default_mono_compile_method (method);
496 static MonoFreeMethodFunc default_mono_free_method = NULL;
499 * mono_install_free_method:
500 * @func: pointer to the MonoFreeMethodFunc used to release a method
502 * This is an internal VM routine, it is used for the engines to
503 * register a handler to release the resources associated with a method.
505 * Methods are freed when no more references to the delegate that holds
506 * them are left.
508 void
509 mono_install_free_method (MonoFreeMethodFunc func)
511 default_mono_free_method = func;
515 * mono_runtime_free_method:
516 * @domain; domain where the method is hosted
517 * @method: method to release
519 * This routine is invoked to free the resources associated with
520 * a method that has been JIT compiled. This is used to discard
521 * methods that were used only temporarily (for example, used in marshalling)
524 void
525 mono_runtime_free_method (MonoDomain *domain, MonoMethod *method)
527 if (default_mono_free_method != NULL)
528 default_mono_free_method (domain, method);
530 mono_free_method (method);
533 static MonoInitVTableFunc init_vtable_func = NULL;
536 * mono_install_init_vtable:
537 * @func: pointer to the function to be installed
539 * Register a function which will be called by the runtime to initialize the
540 * method pointers inside a vtable. The JIT can use this function to load the
541 * vtable from the AOT file for example.
543 void
544 mono_install_init_vtable (MonoInitVTableFunc func)
546 init_vtable_func = func;
550 * The vtables in the root appdomain are assumed to be reachable by other
551 * roots, and we don't use typed allocation in the other domains.
554 /* The sync block is no longer a GC pointer */
555 #define GC_HEADER_BITMAP (0)
557 #define BITMAP_EL_SIZE (sizeof (gsize) * 8)
559 static gsize*
560 compute_class_bitmap (MonoClass *class, gsize *bitmap, int size, int offset, int *max_set, gboolean static_fields)
562 MonoClassField *field;
563 MonoClass *p;
564 guint32 pos;
565 int max_size;
567 if (static_fields)
568 max_size = mono_class_data_size (class) / sizeof (gpointer);
569 else
570 max_size = class->instance_size / sizeof (gpointer);
571 if (max_size >= size) {
572 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
575 for (p = class; p != NULL; p = p->parent) {
576 gpointer iter = NULL;
577 while ((field = mono_class_get_fields (p, &iter))) {
578 MonoType *type;
580 if (static_fields) {
581 if (!(field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA)))
582 continue;
583 } else {
584 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
585 continue;
587 /* FIXME: should not happen, flag as type load error */
588 if (field->type->byref)
589 break;
591 pos = field->offset / sizeof (gpointer);
592 pos += offset;
594 type = mono_type_get_underlying_type (field->type);
595 switch (type->type) {
596 case MONO_TYPE_I:
597 case MONO_TYPE_PTR:
598 case MONO_TYPE_FNPTR:
599 break;
600 /* only UIntPtr is allowed to be GC-tracked and only in mscorlib */
601 case MONO_TYPE_U:
602 #ifdef HAVE_SGEN_GC
603 break;
604 #else
605 if (class->image != mono_defaults.corlib)
606 break;
607 #endif
608 case MONO_TYPE_STRING:
609 case MONO_TYPE_SZARRAY:
610 case MONO_TYPE_CLASS:
611 case MONO_TYPE_OBJECT:
612 case MONO_TYPE_ARRAY:
613 g_assert ((field->offset % sizeof(gpointer)) == 0);
615 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
616 *max_set = MAX (*max_set, pos);
617 break;
618 case MONO_TYPE_GENERICINST:
619 if (!mono_type_generic_inst_is_valuetype (type)) {
620 g_assert ((field->offset % sizeof(gpointer)) == 0);
622 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
623 *max_set = MAX (*max_set, pos);
624 break;
625 } else {
626 /* fall through */
628 case MONO_TYPE_VALUETYPE: {
629 MonoClass *fclass = mono_class_from_mono_type (field->type);
630 if (fclass->has_references) {
631 /* remove the object header */
632 compute_class_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)), max_set, FALSE);
634 break;
636 case MONO_TYPE_I1:
637 case MONO_TYPE_U1:
638 case MONO_TYPE_I2:
639 case MONO_TYPE_U2:
640 case MONO_TYPE_I4:
641 case MONO_TYPE_U4:
642 case MONO_TYPE_I8:
643 case MONO_TYPE_U8:
644 case MONO_TYPE_R4:
645 case MONO_TYPE_R8:
646 case MONO_TYPE_BOOLEAN:
647 case MONO_TYPE_CHAR:
648 break;
649 default:
650 g_assert_not_reached ();
651 break;
654 if (static_fields)
655 break;
657 return bitmap;
660 #if 0
662 * similar to the above, but sets the bits in the bitmap for any non-ref field
663 * and ignores static fields
665 static gsize*
666 compute_class_non_ref_bitmap (MonoClass *class, gsize *bitmap, int size, int offset)
668 MonoClassField *field;
669 MonoClass *p;
670 guint32 pos, pos2;
671 int max_size;
673 max_size = class->instance_size / sizeof (gpointer);
674 if (max_size >= size) {
675 bitmap = g_malloc0 (sizeof (gsize) * ((max_size) + 1));
678 for (p = class; p != NULL; p = p->parent) {
679 gpointer iter = NULL;
680 while ((field = mono_class_get_fields (p, &iter))) {
681 MonoType *type;
683 if (field->type->attrs & (FIELD_ATTRIBUTE_STATIC | FIELD_ATTRIBUTE_HAS_FIELD_RVA))
684 continue;
685 /* FIXME: should not happen, flag as type load error */
686 if (field->type->byref)
687 break;
689 pos = field->offset / sizeof (gpointer);
690 pos += offset;
692 type = mono_type_get_underlying_type (field->type);
693 switch (type->type) {
694 #if SIZEOF_VOID_P == 8
695 case MONO_TYPE_I:
696 case MONO_TYPE_U:
697 case MONO_TYPE_PTR:
698 case MONO_TYPE_FNPTR:
699 #endif
700 case MONO_TYPE_I8:
701 case MONO_TYPE_U8:
702 case MONO_TYPE_R8:
703 if ((((field->offset + 7) / sizeof (gpointer)) + offset) != pos) {
704 pos2 = ((field->offset + 7) / sizeof (gpointer)) + offset;
705 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
707 /* fall through */
708 #if SIZEOF_VOID_P == 4
709 case MONO_TYPE_I:
710 case MONO_TYPE_U:
711 case MONO_TYPE_PTR:
712 case MONO_TYPE_FNPTR:
713 #endif
714 case MONO_TYPE_I4:
715 case MONO_TYPE_U4:
716 case MONO_TYPE_R4:
717 if ((((field->offset + 3) / sizeof (gpointer)) + offset) != pos) {
718 pos2 = ((field->offset + 3) / sizeof (gpointer)) + offset;
719 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
721 /* fall through */
722 case MONO_TYPE_CHAR:
723 case MONO_TYPE_I2:
724 case MONO_TYPE_U2:
725 if ((((field->offset + 1) / sizeof (gpointer)) + offset) != pos) {
726 pos2 = ((field->offset + 1) / sizeof (gpointer)) + offset;
727 bitmap [pos2 / BITMAP_EL_SIZE] |= ((gsize)1) << (pos2 % BITMAP_EL_SIZE);
729 /* fall through */
730 case MONO_TYPE_BOOLEAN:
731 case MONO_TYPE_I1:
732 case MONO_TYPE_U1:
733 bitmap [pos / BITMAP_EL_SIZE] |= ((gsize)1) << (pos % BITMAP_EL_SIZE);
734 break;
735 case MONO_TYPE_STRING:
736 case MONO_TYPE_SZARRAY:
737 case MONO_TYPE_CLASS:
738 case MONO_TYPE_OBJECT:
739 case MONO_TYPE_ARRAY:
740 break;
741 case MONO_TYPE_GENERICINST:
742 if (!mono_type_generic_inst_is_valuetype (type)) {
743 break;
744 } else {
745 /* fall through */
747 case MONO_TYPE_VALUETYPE: {
748 MonoClass *fclass = mono_class_from_mono_type (field->type);
749 /* remove the object header */
750 compute_class_non_ref_bitmap (fclass, bitmap, size, pos - (sizeof (MonoObject) / sizeof (gpointer)));
751 break;
753 default:
754 g_assert_not_reached ();
755 break;
759 return bitmap;
763 * mono_class_insecure_overlapping:
764 * check if a class with explicit layout has references and non-references
765 * fields overlapping.
767 * Returns: TRUE if it is insecure to load the type.
769 gboolean
770 mono_class_insecure_overlapping (MonoClass *klass)
772 int max_set = 0;
773 gsize *bitmap;
774 gsize default_bitmap [4] = {0};
775 gsize *nrbitmap;
776 gsize default_nrbitmap [4] = {0};
777 int i, insecure = FALSE;
778 return FALSE;
780 bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
781 nrbitmap = compute_class_non_ref_bitmap (klass, default_nrbitmap, sizeof (default_nrbitmap) * 8, 0);
783 for (i = 0; i <= max_set; i += sizeof (bitmap [0]) * 8) {
784 int idx = i % (sizeof (bitmap [0]) * 8);
785 if (bitmap [idx] & nrbitmap [idx]) {
786 insecure = TRUE;
787 break;
790 if (bitmap != default_bitmap)
791 g_free (bitmap);
792 if (nrbitmap != default_nrbitmap)
793 g_free (nrbitmap);
794 if (insecure) {
795 g_print ("class %s.%s in assembly %s has overlapping references\n", klass->name_space, klass->name, klass->image->name);
796 return FALSE;
798 return insecure;
800 #endif
802 static void
803 mono_class_compute_gc_descriptor (MonoClass *class)
805 int max_set = 0;
806 gsize *bitmap;
807 gsize default_bitmap [4] = {0};
808 static gboolean gcj_inited = FALSE;
810 if (!gcj_inited) {
811 mono_loader_lock ();
813 mono_register_jit_icall (mono_object_new_ptrfree, "mono_object_new_ptrfree", mono_create_icall_signature ("object ptr"), FALSE);
814 mono_register_jit_icall (mono_object_new_ptrfree_box, "mono_object_new_ptrfree_box", mono_create_icall_signature ("object ptr"), FALSE);
815 mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", mono_create_icall_signature ("object ptr"), FALSE);
817 #ifdef HAVE_GC_GCJ_MALLOC
819 GC_init_gcj_malloc (5, NULL);
821 #ifdef GC_REDIRECT_TO_LOCAL
822 mono_register_jit_icall (GC_local_gcj_malloc, "GC_local_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
823 mono_register_jit_icall (GC_local_gcj_fast_malloc, "GC_local_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
824 #endif
825 mono_register_jit_icall (GC_gcj_malloc, "GC_gcj_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
826 mono_register_jit_icall (GC_gcj_fast_malloc, "GC_gcj_fast_malloc", mono_create_icall_signature ("object int ptr"), FALSE);
827 #endif
828 gcj_inited = TRUE;
829 mono_loader_unlock ();
832 if (!class->inited)
833 mono_class_init (class);
835 if (class->gc_descr_inited)
836 return;
838 class->gc_descr_inited = TRUE;
839 class->gc_descr = GC_NO_DESCRIPTOR;
841 bitmap = default_bitmap;
842 if (class == mono_defaults.string_class) {
843 class->gc_descr = (gpointer)MAKE_STRING_DESCRIPTOR (bitmap, 2);
844 } else if (class->rank) {
845 mono_class_compute_gc_descriptor (class->element_class);
846 #ifdef HAVE_SGEN_GC
847 /* libgc has no usable support for arrays... */
848 if (!class->element_class->valuetype) {
849 gsize abm = 1;
850 class->gc_descr = mono_gc_make_descr_for_array (TRUE, &abm, 1, sizeof (gpointer));
851 /*printf ("new array descriptor: 0x%x for %s.%s\n", class->gc_descr,
852 class->name_space, class->name);*/
853 } else {
854 /* remove the object header */
855 bitmap = compute_class_bitmap (class->element_class, default_bitmap, sizeof (default_bitmap) * 8, - (sizeof (MonoObject) / sizeof (gpointer)), &max_set, FALSE);
856 class->gc_descr = mono_gc_make_descr_for_array (TRUE, bitmap, mono_array_element_size (class) / sizeof (gpointer), mono_array_element_size (class));
857 /*printf ("new vt array descriptor: 0x%x for %s.%s\n", class->gc_descr,
858 class->name_space, class->name);*/
859 if (bitmap != default_bitmap)
860 g_free (bitmap);
862 #endif
863 } else {
864 /*static int count = 0;
865 if (count++ > 58)
866 return;*/
867 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, FALSE);
868 #ifdef HAVE_BOEHM_GC
869 /* It seems there are issues when the bitmap doesn't fit: play it safe */
870 if (max_set >= 30) {
871 /*g_print ("disabling typed alloc (%d) for %s.%s\n", max_set, class->name_space, class->name);*/
872 if (bitmap != default_bitmap)
873 g_free (bitmap);
874 return;
876 #endif
877 class->gc_descr = (gpointer)MAKE_DESCRIPTOR (bitmap, max_set + 1, class->instance_size);
878 /*printf ("new descriptor: %p 0x%x for %s.%s\n", class->gc_descr, bitmap [0], class->name_space, class->name);*/
879 if (bitmap != default_bitmap)
880 g_free (bitmap);
885 * field_is_special_static:
886 * @fklass: The MonoClass to look up.
887 * @field: The MonoClassField describing the field.
889 * Returns: SPECIAL_STATIC_THREAD if the field is thread static, SPECIAL_STATIC_CONTEXT if it is context static,
890 * SPECIAL_STATIC_NONE otherwise.
892 static gint32
893 field_is_special_static (MonoClass *fklass, MonoClassField *field)
895 MonoCustomAttrInfo *ainfo;
896 int i;
897 ainfo = mono_custom_attrs_from_field (fklass, field);
898 if (!ainfo)
899 return FALSE;
900 for (i = 0; i < ainfo->num_attrs; ++i) {
901 MonoClass *klass = ainfo->attrs [i].ctor->klass;
902 if (klass->image == mono_defaults.corlib) {
903 if (strcmp (klass->name, "ThreadStaticAttribute") == 0) {
904 mono_custom_attrs_free (ainfo);
905 return SPECIAL_STATIC_THREAD;
907 else if (strcmp (klass->name, "ContextStaticAttribute") == 0) {
908 mono_custom_attrs_free (ainfo);
909 return SPECIAL_STATIC_CONTEXT;
913 mono_custom_attrs_free (ainfo);
914 return SPECIAL_STATIC_NONE;
917 static MonoVTable *mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class);
920 * mono_class_vtable:
921 * @domain: the application domain
922 * @class: the class to initialize
924 * VTables are domain specific because we create domain specific code, and
925 * they contain the domain specific static class data.
927 MonoVTable *
928 mono_class_vtable (MonoDomain *domain, MonoClass *class)
930 MonoClassRuntimeInfo *runtime_info;
932 g_assert (class);
934 /* this check can be inlined in jitted code, too */
935 runtime_info = class->runtime_info;
936 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id])
937 return runtime_info->domain_vtables [domain->domain_id];
938 return mono_class_create_runtime_vtable (domain, class);
941 static MonoVTable *
942 mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *class)
944 MonoVTable *vt;
945 MonoClassRuntimeInfo *runtime_info, *old_info;
946 MonoClassField *field;
947 char *t;
948 int i;
949 gboolean inited = FALSE;
950 guint32 vtable_size, class_size;
951 guint32 cindex;
952 guint32 constant_cols [MONO_CONSTANT_SIZE];
953 gpointer iter;
954 gpointer *interface_offsets;
956 mono_domain_lock (domain);
957 runtime_info = class->runtime_info;
958 if (runtime_info && runtime_info->max_domain >= domain->domain_id && runtime_info->domain_vtables [domain->domain_id]) {
959 mono_domain_unlock (domain);
960 return runtime_info->domain_vtables [domain->domain_id];
962 if (!class->inited || class->exception_type) {
963 if (!mono_class_init (class) || class->exception_type){
964 MonoException *exc;
965 mono_domain_unlock (domain);
966 exc = mono_class_get_exception_for_failure (class);
967 g_assert (exc);
968 mono_raise_exception (exc);
972 mono_class_init (class);
974 /* FIXME: This should be done by mono_class_init () for dynamic classes as well */
975 if (class->image->dynamic)
976 mono_class_setup_vtable (class);
978 vtable_size = sizeof (gpointer) * (class->max_interface_id + 1) +
979 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
981 mono_stats.used_class_count++;
982 mono_stats.class_vtable_size += vtable_size;
983 interface_offsets = mono_mempool_alloc0 (domain->mp, vtable_size);
985 vt = (MonoVTable*) (interface_offsets + class->max_interface_id + 1);
986 vt->klass = class;
987 vt->rank = class->rank;
988 vt->domain = domain;
990 mono_class_compute_gc_descriptor (class);
992 * We can't use typed allocation in the non-root domains, since the
993 * collector needs the GC descriptor stored in the vtable even after
994 * the mempool containing the vtable is destroyed when the domain is
995 * unloaded. An alternative might be to allocate vtables in the GC
996 * heap, but this does not seem to work (it leads to crashes inside
997 * libgc). If that approach is tried, two gc descriptors need to be
998 * allocated for each class: one for the root domain, and one for all
999 * other domains. The second descriptor should contain a bit for the
1000 * vtable field in MonoObject, since we can no longer assume the
1001 * vtable is reachable by other roots after the appdomain is unloaded.
1003 #ifdef HAVE_BOEHM_GC
1004 if (domain != mono_get_root_domain ())
1005 vt->gc_descr = GC_NO_DESCRIPTOR;
1006 else
1007 #endif
1008 vt->gc_descr = class->gc_descr;
1010 if ((class_size = mono_class_data_size (class))) {
1011 if (class->has_static_refs) {
1012 gpointer statics_gc_descr;
1013 int max_set = 0;
1014 gsize default_bitmap [4] = {0};
1015 gsize *bitmap;
1017 bitmap = compute_class_bitmap (class, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE);
1018 /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], class->name_space, class->name, class_size);*/
1019 statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set? max_set + 1: 0);
1020 vt->data = mono_gc_alloc_fixed (class_size, statics_gc_descr);
1021 mono_domain_add_class_static_data (domain, class, vt->data, NULL);
1022 if (bitmap != default_bitmap)
1023 g_free (bitmap);
1024 } else {
1025 vt->data = mono_mempool_alloc0 (domain->mp, class_size);
1027 mono_stats.class_static_data_size += class_size;
1030 cindex = -1;
1031 iter = NULL;
1032 while ((field = mono_class_get_fields (class, &iter))) {
1033 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1034 continue;
1035 if (mono_field_is_deleted (field))
1036 continue;
1037 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1038 gint32 special_static = class->no_special_static_fields ? SPECIAL_STATIC_NONE : field_is_special_static (class, field);
1039 if (special_static != SPECIAL_STATIC_NONE) {
1040 guint32 size, offset;
1041 gint32 align;
1042 size = mono_type_size (field->type, &align);
1043 offset = mono_alloc_special_static_data (special_static, size, align);
1044 if (!domain->special_static_fields)
1045 domain->special_static_fields = g_hash_table_new (NULL, NULL);
1046 g_hash_table_insert (domain->special_static_fields, field, GUINT_TO_POINTER (offset));
1047 continue;
1050 if ((field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
1051 MonoClass *fklass = mono_class_from_mono_type (field->type);
1052 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT));
1053 t = (char*)vt->data + field->offset;
1054 if (fklass->valuetype) {
1055 memcpy (t, field->data, mono_class_value_size (fklass, NULL));
1056 } else {
1057 /* it's a pointer type: add check */
1058 g_assert ((fklass->byval_arg.type == MONO_TYPE_PTR) || (fklass->byval_arg.type == MONO_TYPE_FNPTR));
1059 *t = *(char *)field->data;
1061 continue;
1063 if (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT))
1064 continue;
1066 /* later do this only on demand if needed */
1067 if (!field->data) {
1068 cindex = mono_metadata_get_constant_index (class->image, mono_class_get_field_token (field), cindex + 1);
1069 g_assert (cindex);
1070 g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA));
1072 mono_metadata_decode_row (&class->image->tables [MONO_TABLE_CONSTANT], cindex - 1, constant_cols, MONO_CONSTANT_SIZE);
1073 field->def_type = constant_cols [MONO_CONSTANT_TYPE];
1074 field->data = (gpointer)mono_metadata_blob_heap (class->image, constant_cols [MONO_CONSTANT_VALUE]);
1079 vt->max_interface_id = class->max_interface_id;
1081 /* initialize interface offsets */
1082 for (i = 0; i <= class->max_interface_id; ++i) {
1083 int slot = class->interface_offsets [i];
1084 if (slot >= 0)
1085 interface_offsets [class->max_interface_id - i] = &(vt->vtable [slot]);
1089 * arch_create_jit_trampoline () can recursively call this function again
1090 * because it compiles icall methods right away.
1092 /* FIXME: class_vtable_hash is basically obsolete now: remove as soon
1093 * as we change the code in appdomain.c to invalidate vtables by
1094 * looking at the possible MonoClasses created for the domain.
1096 g_hash_table_insert (domain->class_vtable_hash, class, vt);
1097 /* class->runtime_info is protected by the loader lock, both when
1098 * it it enlarged and when it is stored info.
1100 mono_loader_lock ();
1101 old_info = class->runtime_info;
1102 if (old_info && old_info->max_domain >= domain->domain_id) {
1103 /* someone already created a large enough runtime info */
1104 old_info->domain_vtables [domain->domain_id] = vt;
1105 } else {
1106 int new_size = domain->domain_id;
1107 if (old_info)
1108 new_size = MAX (new_size, old_info->max_domain);
1109 new_size++;
1110 /* make the new size a power of two */
1111 i = 2;
1112 while (new_size > i)
1113 i <<= 1;
1114 new_size = i;
1115 /* this is a bounded memory retention issue: may want to
1116 * handle it differently when we'll have a rcu-like system.
1118 runtime_info = mono_mempool_alloc0 (class->image->mempool, sizeof (MonoClassRuntimeInfo) + new_size * sizeof (gpointer));
1119 runtime_info->max_domain = new_size - 1;
1120 /* copy the stuff from the older info */
1121 if (old_info) {
1122 memcpy (runtime_info->domain_vtables, old_info->domain_vtables, (old_info->max_domain + 1) * sizeof (gpointer));
1124 runtime_info->domain_vtables [domain->domain_id] = vt;
1125 /* keep this last (add membarrier) */
1126 class->runtime_info = runtime_info;
1128 mono_loader_unlock ();
1130 /* initialize vtable */
1131 if (init_vtable_func)
1132 inited = init_vtable_func (vt);
1134 if (!inited) {
1135 mono_class_setup_vtable (class);
1137 for (i = 0; i < class->vtable_size; ++i) {
1138 MonoMethod *cm;
1140 if ((cm = class->vtable [i])) {
1141 if (mono_method_signature (cm)->generic_param_count)
1142 vt->vtable [i] = cm;
1143 else
1144 vt->vtable [i] = arch_create_jit_trampoline (cm);
1149 mono_domain_unlock (domain);
1151 /* Initialization is now complete, we can throw if the InheritanceDemand aren't satisfied */
1152 if (mono_is_security_manager_active () && (class->exception_type == MONO_EXCEPTION_SECURITY_INHERITANCEDEMAND)) {
1153 MonoException *exc = mono_class_get_exception_for_failure (class);
1154 g_assert (exc);
1155 mono_raise_exception (exc);
1158 /* make sure the the parent is initialized */
1159 if (class->parent)
1160 mono_class_vtable (domain, class->parent);
1162 vt->type = mono_type_get_object (domain, &class->byval_arg);
1163 if (class->contextbound)
1164 vt->remote = 1;
1165 else
1166 vt->remote = 0;
1168 return vt;
1172 * mono_class_proxy_vtable:
1173 * @domain: the application domain
1174 * @remove_class: the remote class
1176 * Creates a vtable for transparent proxies. It is basically
1177 * a copy of the real vtable of the class wrapped in @remote_class,
1178 * but all function pointers invoke the remoting functions, and
1179 * vtable->klass points to the transparent proxy class, and not to @class.
1181 static MonoVTable *
1182 mono_class_proxy_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRemotingTarget target_type)
1184 MonoVTable *vt, *pvt;
1185 int i, j, vtsize, max_interface_id, extra_interface_vtsize = 0;
1186 MonoClass *k;
1187 GSList *extra_interfaces = NULL;
1188 MonoClass *class = remote_class->proxy_class;
1189 gpointer *interface_offsets;
1191 vt = mono_class_vtable (domain, class);
1192 max_interface_id = vt->max_interface_id;
1194 /* Calculate vtable space for extra interfaces */
1195 for (j = 0; j < remote_class->interface_count; j++) {
1196 MonoClass* iclass = remote_class->interfaces[j];
1197 GPtrArray *ifaces;
1198 int method_count;
1200 if (iclass->interface_id <= class->max_interface_id && class->interface_offsets[iclass->interface_id] != -1)
1201 continue; /* interface implemented by the class */
1202 if (g_slist_find (extra_interfaces, iclass))
1203 continue;
1205 extra_interfaces = g_slist_prepend (extra_interfaces, iclass);
1207 method_count = mono_class_num_methods (iclass);
1209 ifaces = mono_class_get_implemented_interfaces (iclass);
1210 if (ifaces) {
1211 for (i = 0; i < ifaces->len; ++i) {
1212 MonoClass *ic = g_ptr_array_index (ifaces, i);
1213 if (ic->interface_id <= class->max_interface_id && class->interface_offsets[ic->interface_id] != -1)
1214 continue; /* interface implemented by the class */
1215 if (g_slist_find (extra_interfaces, ic))
1216 continue;
1217 extra_interfaces = g_slist_prepend (extra_interfaces, ic);
1218 method_count += mono_class_num_methods (ic);
1220 g_ptr_array_free (ifaces, TRUE);
1223 extra_interface_vtsize += method_count * sizeof (gpointer);
1224 if (iclass->max_interface_id > max_interface_id) max_interface_id = iclass->max_interface_id;
1227 vtsize = sizeof (gpointer) * (max_interface_id + 1) +
1228 sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer);
1230 mono_stats.class_vtable_size += vtsize + extra_interface_vtsize;
1232 interface_offsets = mono_mempool_alloc0 (domain->mp, vtsize + extra_interface_vtsize);
1233 pvt = (MonoVTable*)(interface_offsets + max_interface_id + 1);
1234 memcpy (pvt, vt, sizeof (MonoVTable) + class->vtable_size * sizeof (gpointer));
1236 pvt->klass = mono_defaults.transparent_proxy_class;
1237 /* we need to keep the GC descriptor for a transparent proxy or we confuse the precise GC */
1238 pvt->gc_descr = mono_defaults.transparent_proxy_class->gc_descr;
1240 /* initialize vtable */
1241 mono_class_setup_vtable (class);
1242 for (i = 0; i < class->vtable_size; ++i) {
1243 MonoMethod *cm;
1245 if ((cm = class->vtable [i]))
1246 pvt->vtable [i] = arch_create_remoting_trampoline (cm, target_type);
1249 if (class->flags & TYPE_ATTRIBUTE_ABSTRACT) {
1250 /* create trampolines for abstract methods */
1251 for (k = class; k; k = k->parent) {
1252 MonoMethod* m;
1253 gpointer iter = NULL;
1254 while ((m = mono_class_get_methods (k, &iter)))
1255 if (!pvt->vtable [m->slot])
1256 pvt->vtable [m->slot] = arch_create_remoting_trampoline (m, target_type);
1260 pvt->max_interface_id = max_interface_id;
1262 /* initialize interface offsets */
1263 for (i = 0; i <= class->max_interface_id; ++i) {
1264 int slot = class->interface_offsets [i];
1265 if (slot >= 0)
1266 interface_offsets [max_interface_id - i] = &(pvt->vtable [slot]);
1269 if (extra_interfaces) {
1270 int slot = class->vtable_size;
1271 MonoClass* interf;
1272 gpointer iter;
1273 MonoMethod* cm;
1274 GSList *list_item;
1276 /* Create trampolines for the methods of the interfaces */
1277 for (list_item = extra_interfaces; list_item != NULL; list_item=list_item->next) {
1278 interf = list_item->data;
1279 interface_offsets [max_interface_id - interf->interface_id] = &pvt->vtable [slot];
1281 iter = NULL;
1282 j = 0;
1283 while ((cm = mono_class_get_methods (interf, &iter)))
1284 pvt->vtable [slot + j++] = arch_create_remoting_trampoline (cm, target_type);
1286 slot += mono_class_num_methods (interf);
1288 g_slist_free (extra_interfaces);
1291 return pvt;
1295 * mono_class_has_special_static_fields:
1297 * Returns whenever @klass has any thread/context static fields.
1299 gboolean
1300 mono_class_has_special_static_fields (MonoClass *klass)
1302 MonoClassField *field;
1303 gpointer iter;
1305 iter = NULL;
1306 while ((field = mono_class_get_fields (klass, &iter))) {
1307 if (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC))
1308 continue;
1309 if (mono_field_is_deleted (field))
1310 continue;
1311 if (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL)) {
1312 if (field_is_special_static (klass, field) != SPECIAL_STATIC_NONE)
1313 return TRUE;
1317 return FALSE;
1321 * create_remote_class_key:
1322 * Creates an array of pointers that can be used as a hash key for a remote class.
1323 * The first element of the array is the number of pointers.
1325 static gpointer*
1326 create_remote_class_key (MonoRemoteClass *remote_class, MonoClass *extra_class)
1328 gpointer *key;
1329 int i, j;
1331 if (remote_class == NULL) {
1332 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1333 key = g_malloc (sizeof(gpointer) * 3);
1334 key [0] = GINT_TO_POINTER (2);
1335 key [1] = mono_defaults.marshalbyrefobject_class;
1336 key [2] = extra_class;
1337 } else {
1338 key = g_malloc (sizeof(gpointer) * 2);
1339 key [0] = GINT_TO_POINTER (1);
1340 key [1] = extra_class;
1342 } else {
1343 if (extra_class != NULL && (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE)) {
1344 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 3));
1345 key [0] = GINT_TO_POINTER (remote_class->interface_count + 2);
1346 key [1] = remote_class->proxy_class;
1348 // Keep the list of interfaces sorted
1349 for (i = 0, j = 2; i < remote_class->interface_count; i++, j++) {
1350 if (extra_class && remote_class->interfaces [i] > extra_class) {
1351 key [j++] = extra_class;
1352 extra_class = NULL;
1354 key [j] = remote_class->interfaces [i];
1356 if (extra_class)
1357 key [j] = extra_class;
1358 } else {
1359 // Replace the old class. The interface list is the same
1360 key = g_malloc (sizeof(gpointer) * (remote_class->interface_count + 2));
1361 key [0] = GINT_TO_POINTER (remote_class->interface_count + 1);
1362 key [1] = extra_class != NULL ? extra_class : remote_class->proxy_class;
1363 for (i = 0; i < remote_class->interface_count; i++)
1364 key [2 + i] = remote_class->interfaces [i];
1368 return key;
1372 * copy_remote_class_key:
1374 * Make a copy of KEY in the mempool MP and return the copy.
1376 static gpointer*
1377 copy_remote_class_key (MonoMemPool *mp, gpointer *key)
1379 int key_size = (GPOINTER_TO_UINT (key [0]) + 1) * sizeof (gpointer);
1380 gpointer *mp_key = mono_mempool_alloc (mp, key_size);
1382 memcpy (mp_key, key, key_size);
1384 return mp_key;
1388 * mono_remote_class:
1389 * @domain: the application domain
1390 * @class_name: name of the remote class
1392 * Creates and initializes a MonoRemoteClass object for a remote type.
1395 MonoRemoteClass*
1396 mono_remote_class (MonoDomain *domain, MonoString *class_name, MonoClass *proxy_class)
1398 MonoRemoteClass *rc;
1399 gpointer* key, *mp_key;
1401 key = create_remote_class_key (NULL, proxy_class);
1403 mono_domain_lock (domain);
1404 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
1406 if (rc) {
1407 g_free (key);
1408 mono_domain_unlock (domain);
1409 return rc;
1412 mp_key = copy_remote_class_key (domain->mp, key);
1413 g_free (key);
1414 key = mp_key;
1416 if (proxy_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1417 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*));
1418 rc->interface_count = 1;
1419 rc->interfaces [0] = proxy_class;
1420 rc->proxy_class = mono_defaults.marshalbyrefobject_class;
1421 } else {
1422 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass));
1423 rc->interface_count = 0;
1424 rc->proxy_class = proxy_class;
1427 rc->default_vtable = NULL;
1428 rc->xdomain_vtable = NULL;
1429 rc->proxy_class_name = mono_string_to_utf8_mp (domain->mp, class_name);
1431 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1433 mono_domain_unlock (domain);
1434 return rc;
1438 * clone_remote_class:
1439 * Creates a copy of the remote_class, adding the provided class or interface
1441 static MonoRemoteClass*
1442 clone_remote_class (MonoDomain *domain, MonoRemoteClass* remote_class, MonoClass *extra_class)
1444 MonoRemoteClass *rc;
1445 gpointer* key, *mp_key;
1447 key = create_remote_class_key (remote_class, extra_class);
1448 rc = g_hash_table_lookup (domain->proxy_vtable_hash, key);
1449 if (rc != NULL) {
1450 g_free (key);
1451 return rc;
1454 mp_key = copy_remote_class_key (domain->mp, key);
1455 g_free (key);
1456 key = mp_key;
1458 if (extra_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1459 int i,j;
1460 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * (remote_class->interface_count + 1));
1461 rc->proxy_class = remote_class->proxy_class;
1462 rc->interface_count = remote_class->interface_count + 1;
1464 // Keep the list of interfaces sorted, since the hash key of
1465 // the remote class depends on this
1466 for (i = 0, j = 0; i < remote_class->interface_count; i++, j++) {
1467 if (remote_class->interfaces [i] > extra_class && i == j)
1468 rc->interfaces [j++] = extra_class;
1469 rc->interfaces [j] = remote_class->interfaces [i];
1471 if (i == j)
1472 rc->interfaces [j] = extra_class;
1473 } else {
1474 // Replace the old class. The interface array is the same
1475 rc = mono_mempool_alloc (domain->mp, sizeof(MonoRemoteClass) + sizeof(MonoClass*) * remote_class->interface_count);
1476 rc->proxy_class = extra_class;
1477 rc->interface_count = remote_class->interface_count;
1478 if (rc->interface_count > 0)
1479 memcpy (rc->interfaces, remote_class->interfaces, rc->interface_count * sizeof (MonoClass*));
1482 rc->default_vtable = NULL;
1483 rc->xdomain_vtable = NULL;
1484 rc->proxy_class_name = remote_class->proxy_class_name;
1486 g_hash_table_insert (domain->proxy_vtable_hash, key, rc);
1488 return rc;
1491 gpointer
1492 mono_remote_class_vtable (MonoDomain *domain, MonoRemoteClass *remote_class, MonoRealProxy *rp)
1494 mono_domain_lock (domain);
1495 if (rp->target_domain_id != -1) {
1496 if (remote_class->xdomain_vtable == NULL)
1497 remote_class->xdomain_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_APPDOMAIN);
1498 mono_domain_unlock (domain);
1499 return remote_class->xdomain_vtable;
1501 if (remote_class->default_vtable == NULL) {
1502 MonoType *type;
1503 MonoClass *klass;
1504 type = ((MonoReflectionType *)rp->class_to_proxy)->type;
1505 klass = mono_class_from_mono_type (type);
1506 if ((klass->is_com_object || (mono_defaults.com_object_class && klass == mono_defaults.com_object_class)) && !mono_class_vtable (mono_domain_get (), klass)->remote)
1507 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_COMINTEROP);
1508 else
1509 remote_class->default_vtable = mono_class_proxy_vtable (domain, remote_class, MONO_REMOTING_TARGET_UNKNOWN);
1512 mono_domain_unlock (domain);
1513 return remote_class->default_vtable;
1517 * mono_upgrade_remote_class:
1518 * @domain: the application domain
1519 * @tproxy: the proxy whose remote class has to be upgraded.
1520 * @klass: class to which the remote class can be casted.
1522 * Updates the vtable of the remote class by adding the necessary method slots
1523 * and interface offsets so it can be safely casted to klass. klass can be a
1524 * class or an interface.
1526 void
1527 mono_upgrade_remote_class (MonoDomain *domain, MonoObject *proxy_object, MonoClass *klass)
1529 MonoTransparentProxy *tproxy;
1530 MonoRemoteClass *remote_class;
1531 gboolean redo_vtable;
1533 mono_domain_lock (domain);
1535 tproxy = (MonoTransparentProxy*) proxy_object;
1536 remote_class = tproxy->remote_class;
1538 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1539 int i;
1540 redo_vtable = TRUE;
1541 for (i = 0; i < remote_class->interface_count && redo_vtable; i++)
1542 if (remote_class->interfaces [i] == klass)
1543 redo_vtable = FALSE;
1545 else {
1546 redo_vtable = (remote_class->proxy_class != klass);
1549 if (redo_vtable) {
1550 tproxy->remote_class = clone_remote_class (domain, remote_class, klass);
1551 proxy_object->vtable = mono_remote_class_vtable (domain, tproxy->remote_class, tproxy->rp);
1554 mono_domain_unlock (domain);
1559 * mono_object_get_virtual_method:
1560 * @obj: object to operate on.
1561 * @method: method
1563 * Retrieves the MonoMethod that would be called on obj if obj is passed as
1564 * the instance of a callvirt of method.
1566 MonoMethod*
1567 mono_object_get_virtual_method (MonoObject *obj, MonoMethod *method)
1569 MonoClass *klass;
1570 MonoMethod **vtable;
1571 gboolean is_proxy;
1572 MonoMethod *res = NULL;
1574 klass = mono_object_class (obj);
1575 if (klass == mono_defaults.transparent_proxy_class) {
1576 klass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
1577 is_proxy = TRUE;
1578 } else {
1579 is_proxy = FALSE;
1582 if (!is_proxy && ((method->flags & METHOD_ATTRIBUTE_FINAL) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)))
1583 return method;
1585 mono_class_setup_vtable (klass);
1586 vtable = klass->vtable;
1588 /* check method->slot is a valid index: perform isinstance? */
1589 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
1590 if (!is_proxy)
1591 res = vtable [klass->interface_offsets [method->klass->interface_id] + method->slot];
1592 } else {
1593 if (method->slot != -1)
1594 res = vtable [method->slot];
1597 if (is_proxy) {
1598 if (!res) res = method; /* It may be an interface or abstract class method */
1599 res = mono_marshal_get_remoting_invoke (res);
1602 g_assert (res);
1604 return res;
1607 static MonoObject*
1608 dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
1610 g_error ("runtime invoke called on uninitialized runtime");
1611 return NULL;
1614 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
1617 * mono_runtime_invoke:
1618 * @method: method to invoke
1619 * @obJ: object instance
1620 * @params: arguments to the method
1621 * @exc: exception information.
1623 * Invokes the method represented by @method on the object @obj.
1625 * obj is the 'this' pointer, it should be NULL for static
1626 * methods, a MonoObject* for object instances and a pointer to
1627 * the value type for value types.
1629 * The params array contains the arguments to the method with the
1630 * same convention: MonoObject* pointers for object instances and
1631 * pointers to the value type otherwise.
1633 * From unmanaged code you'll usually use the
1634 * mono_runtime_invoke() variant.
1636 * Note that this function doesn't handle virtual methods for
1637 * you, it will exec the exact method you pass: we still need to
1638 * expose a function to lookup the derived class implementation
1639 * of a virtual method (there are examples of this in the code,
1640 * though).
1642 * You can pass NULL as the exc argument if you don't want to
1643 * catch exceptions, otherwise, *exc will be set to the exception
1644 * thrown, if any. if an exception is thrown, you can't use the
1645 * MonoObject* result from the function.
1647 * If the method returns a value type, it is boxed in an object
1648 * reference.
1650 MonoObject*
1651 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
1653 return default_mono_runtime_invoke (method, obj, params, exc);
1656 static void
1657 set_value (MonoType *type, void *dest, void *value, int deref_pointer)
1659 int t;
1660 if (type->byref) {
1661 gpointer *p = (gpointer*)dest;
1662 *p = value;
1663 return;
1665 t = type->type;
1666 handle_enum:
1667 switch (t) {
1668 case MONO_TYPE_BOOLEAN:
1669 case MONO_TYPE_I1:
1670 case MONO_TYPE_U1: {
1671 guint8 *p = (guint8*)dest;
1672 *p = value ? *(guint8*)value : 0;
1673 return;
1675 case MONO_TYPE_I2:
1676 case MONO_TYPE_U2:
1677 case MONO_TYPE_CHAR: {
1678 guint16 *p = (guint16*)dest;
1679 *p = value ? *(guint16*)value : 0;
1680 return;
1682 #if SIZEOF_VOID_P == 4
1683 case MONO_TYPE_I:
1684 case MONO_TYPE_U:
1685 #endif
1686 case MONO_TYPE_I4:
1687 case MONO_TYPE_U4: {
1688 gint32 *p = (gint32*)dest;
1689 *p = value ? *(gint32*)value : 0;
1690 return;
1692 #if SIZEOF_VOID_P == 8
1693 case MONO_TYPE_I:
1694 case MONO_TYPE_U:
1695 #endif
1696 case MONO_TYPE_I8:
1697 case MONO_TYPE_U8: {
1698 gint64 *p = (gint64*)dest;
1699 *p = value ? *(gint64*)value : 0;
1700 return;
1702 case MONO_TYPE_R4: {
1703 float *p = (float*)dest;
1704 *p = value ? *(float*)value : 0;
1705 return;
1707 case MONO_TYPE_R8: {
1708 double *p = (double*)dest;
1709 *p = value ? *(double*)value : 0;
1710 return;
1712 case MONO_TYPE_STRING:
1713 case MONO_TYPE_SZARRAY:
1714 case MONO_TYPE_CLASS:
1715 case MONO_TYPE_OBJECT:
1716 case MONO_TYPE_ARRAY:
1717 mono_gc_wbarrier_generic_store (dest, deref_pointer? *(gpointer*)value: value);
1718 return;
1719 case MONO_TYPE_FNPTR:
1720 case MONO_TYPE_PTR: {
1721 gpointer *p = (gpointer*)dest;
1722 *p = deref_pointer? *(gpointer*)value: value;
1723 return;
1725 case MONO_TYPE_VALUETYPE:
1726 /* note that 't' and 'type->type' can be different */
1727 if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
1728 t = type->data.klass->enum_basetype->type;
1729 goto handle_enum;
1730 } else {
1731 int size;
1732 size = mono_class_value_size (mono_class_from_mono_type (type), NULL);
1733 if (value == NULL)
1734 memset (dest, 0, size);
1735 else
1736 memcpy (dest, value, size);
1738 return;
1739 case MONO_TYPE_GENERICINST:
1740 t = type->data.generic_class->container_class->byval_arg.type;
1741 goto handle_enum;
1742 default:
1743 g_warning ("got type %x", type->type);
1744 g_assert_not_reached ();
1749 * mono_field_set_value:
1750 * @obj: Instance object
1751 * @field: MonoClassField describing the field to set
1752 * @value: The value to be set
1754 * Sets the value of the field described by @field in the object instance @obj
1755 * to the value passed in @value. This method should only be used for instance
1756 * fields. For static fields, use mono_field_static_set_value.
1758 * The value must be on the native format of the field type.
1760 void
1761 mono_field_set_value (MonoObject *obj, MonoClassField *field, void *value)
1763 void *dest;
1765 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
1767 dest = (char*)obj + field->offset;
1768 set_value (field->type, dest, value, FALSE);
1772 * mono_field_static_set_value:
1773 * @field: MonoClassField describing the field to set
1774 * @value: The value to be set
1776 * Sets the value of the static field described by @field
1777 * to the value passed in @value.
1779 * The value must be on the native format of the field type.
1781 void
1782 mono_field_static_set_value (MonoVTable *vt, MonoClassField *field, void *value)
1784 void *dest;
1786 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
1787 /* you cant set a constant! */
1788 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
1790 dest = (char*)vt->data + field->offset;
1791 set_value (field->type, dest, value, FALSE);
1794 /* Used by the debugger */
1795 void *
1796 mono_vtable_get_static_field_data (MonoVTable *vt)
1798 return vt->data;
1802 * mono_field_get_value:
1803 * @obj: Object instance
1804 * @field: MonoClassField describing the field to fetch information from
1805 * @value: pointer to the location where the value will be stored
1807 * Use this routine to get the value of the field @field in the object
1808 * passed.
1810 * The pointer provided by value must be of the field type, for reference
1811 * types this is a MonoObject*, for value types its the actual pointer to
1812 * the value type.
1814 * For example:
1815 * int i;
1816 * mono_field_get_value (obj, int_field, &i);
1818 void
1819 mono_field_get_value (MonoObject *obj, MonoClassField *field, void *value)
1821 void *src;
1823 g_return_if_fail (!(field->type->attrs & FIELD_ATTRIBUTE_STATIC));
1825 src = (char*)obj + field->offset;
1826 set_value (field->type, value, src, TRUE);
1830 * mono_field_get_value_object:
1831 * @domain: domain where the object will be created (if boxing)
1832 * @field: MonoClassField describing the field to fetch information from
1833 * @obj: The object instance for the field.
1835 * Returns: a new MonoObject with the value from the given field. If the
1836 * field represents a value type, the value is boxed.
1839 MonoObject *
1840 mono_field_get_value_object (MonoDomain *domain, MonoClassField *field, MonoObject *obj)
1842 MonoObject *o;
1843 MonoClass *klass;
1844 MonoVTable *vtable = NULL;
1845 gchar *v;
1846 gboolean is_static = FALSE;
1847 gboolean is_ref = FALSE;
1849 switch (field->type->type) {
1850 case MONO_TYPE_STRING:
1851 case MONO_TYPE_OBJECT:
1852 case MONO_TYPE_CLASS:
1853 case MONO_TYPE_ARRAY:
1854 case MONO_TYPE_SZARRAY:
1855 is_ref = TRUE;
1856 break;
1857 case MONO_TYPE_U1:
1858 case MONO_TYPE_I1:
1859 case MONO_TYPE_BOOLEAN:
1860 case MONO_TYPE_U2:
1861 case MONO_TYPE_I2:
1862 case MONO_TYPE_CHAR:
1863 case MONO_TYPE_U:
1864 case MONO_TYPE_I:
1865 case MONO_TYPE_U4:
1866 case MONO_TYPE_I4:
1867 case MONO_TYPE_R4:
1868 case MONO_TYPE_U8:
1869 case MONO_TYPE_I8:
1870 case MONO_TYPE_R8:
1871 case MONO_TYPE_VALUETYPE:
1872 is_ref = field->type->byref;
1873 break;
1874 case MONO_TYPE_GENERICINST:
1875 is_ref = !field->type->data.generic_class->container_class->valuetype;
1876 break;
1877 default:
1878 g_error ("type 0x%x not handled in "
1879 "mono_field_get_value_object", field->type->type);
1880 return NULL;
1883 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
1884 is_static = TRUE;
1885 vtable = mono_class_vtable (domain, field->parent);
1886 if (!vtable->initialized)
1887 mono_runtime_class_init (vtable);
1890 if (is_ref) {
1891 if (is_static) {
1892 mono_field_static_get_value (vtable, field, &o);
1893 } else {
1894 mono_field_get_value (obj, field, &o);
1896 return o;
1899 /* boxed value type */
1900 klass = mono_class_from_mono_type (field->type);
1901 o = mono_object_new (domain, klass);
1902 v = ((gchar *) o) + sizeof (MonoObject);
1903 if (is_static) {
1904 mono_field_static_get_value (vtable, field, v);
1905 } else {
1906 mono_field_get_value (obj, field, v);
1909 return o;
1913 mono_get_constant_value_from_blob (MonoDomain* domain, MonoTypeEnum type, const char *blob, void *value)
1915 int retval = 0;
1916 const char *p = blob;
1917 mono_metadata_decode_blob_size (p, &p);
1919 switch (type) {
1920 case MONO_TYPE_BOOLEAN:
1921 case MONO_TYPE_U1:
1922 case MONO_TYPE_I1:
1923 *(guint8 *) value = *p;
1924 break;
1925 case MONO_TYPE_CHAR:
1926 case MONO_TYPE_U2:
1927 case MONO_TYPE_I2:
1928 *(guint16*) value = read16 (p);
1929 break;
1930 case MONO_TYPE_U4:
1931 case MONO_TYPE_I4:
1932 *(guint32*) value = read32 (p);
1933 break;
1934 case MONO_TYPE_U8:
1935 case MONO_TYPE_I8:
1936 *(guint64*) value = read64 (p);
1937 break;
1938 case MONO_TYPE_R4:
1939 readr4 (p, (float*) value);
1940 break;
1941 case MONO_TYPE_R8:
1942 readr8 (p, (double*) value);
1943 break;
1944 case MONO_TYPE_STRING:
1945 *(gpointer*) value = mono_ldstr_metdata_sig (domain, blob);
1946 break;
1947 case MONO_TYPE_CLASS:
1948 *(gpointer*) value = NULL;
1949 break;
1950 default:
1951 retval = -1;
1952 g_warning ("type 0x%02x should not be in constant table", type);
1954 return retval;
1957 static void
1958 get_default_field_value (MonoDomain* domain, MonoClassField *field, void *value)
1960 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_HAS_DEFAULT);
1961 mono_get_constant_value_from_blob (domain, field->def_type, field->data, value);
1965 * mono_field_static_get_value:
1966 * @vt: vtable to the object
1967 * @field: MonoClassField describing the field to fetch information from
1968 * @value: where the value is returned
1970 * Use this routine to get the value of the static field @field value.
1972 * The pointer provided by value must be of the field type, for reference
1973 * types this is a MonoObject*, for value types its the actual pointer to
1974 * the value type.
1976 * For example:
1977 * int i;
1978 * mono_field_static_get_value (vt, int_field, &i);
1980 void
1981 mono_field_static_get_value (MonoVTable *vt, MonoClassField *field, void *value)
1983 void *src;
1985 g_return_if_fail (field->type->attrs & FIELD_ATTRIBUTE_STATIC);
1987 if (field->type->attrs & FIELD_ATTRIBUTE_LITERAL) {
1988 get_default_field_value (vt->domain, field, value);
1989 return;
1992 src = (char*)vt->data + field->offset;
1993 set_value (field->type, value, src, TRUE);
1997 * mono_property_set_value:
1998 * @prop: MonoProperty to set
1999 * @obj: instance object on which to act
2000 * @params: parameters to pass to the propery
2001 * @exc: optional exception
2003 * Invokes the property's set method with the given arguments on the
2004 * object instance obj (or NULL for static properties).
2006 * You can pass NULL as the exc argument if you don't want to
2007 * catch exceptions, otherwise, *exc will be set to the exception
2008 * thrown, if any. if an exception is thrown, you can't use the
2009 * MonoObject* result from the function.
2011 void
2012 mono_property_set_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2014 default_mono_runtime_invoke (prop->set, obj, params, exc);
2018 * mono_property_get_value:
2019 * @prop: MonoProperty to fetch
2020 * @obj: instance object on which to act
2021 * @params: parameters to pass to the propery
2022 * @exc: optional exception
2024 * Invokes the property's get method with the given arguments on the
2025 * object instance obj (or NULL for static properties).
2027 * You can pass NULL as the exc argument if you don't want to
2028 * catch exceptions, otherwise, *exc will be set to the exception
2029 * thrown, if any. if an exception is thrown, you can't use the
2030 * MonoObject* result from the function.
2032 * Returns: the value from invoking the get method on the property.
2034 MonoObject*
2035 mono_property_get_value (MonoProperty *prop, void *obj, void **params, MonoObject **exc)
2037 return default_mono_runtime_invoke (prop->get, obj, params, exc);
2041 * mono_nullable_init:
2042 * @buf: The nullable structure to initialize.
2043 * @value: the value to initialize from
2044 * @klass: the type for the object
2046 * Initialize the nullable structure pointed to by @buf from @value which
2047 * should be a boxed value type. The size of @buf should be able to hold
2048 * as much data as the @klass->instance_size (which is the number of bytes
2049 * that will be copies).
2051 * Since Nullables have variable structure, we can not define a C
2052 * structure for them.
2054 void
2055 mono_nullable_init (guint8 *buf, MonoObject *value, MonoClass *klass)
2057 MonoClass *param_class = klass->cast_class;
2059 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2060 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2062 *(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject)) = value ? 1 : 0;
2063 if (value)
2064 memcpy (buf + klass->fields [0].offset - sizeof (MonoObject), mono_object_unbox (value), mono_class_value_size (param_class, NULL));
2065 else
2066 memset (buf + klass->fields [0].offset - sizeof (MonoObject), 0, mono_class_value_size (param_class, NULL));
2070 * mono_nullable_box:
2071 * @buf: The buffer representing the data to be boxed
2072 * @klass: the type to box it as.
2074 * Creates a boxed vtype or NULL from the Nullable structure pointed to by
2075 * @buf.
2077 MonoObject*
2078 mono_nullable_box (guint8 *buf, MonoClass *klass)
2080 MonoClass *param_class = klass->cast_class;
2082 g_assert (mono_class_from_mono_type (klass->fields [0].type) == param_class);
2083 g_assert (mono_class_from_mono_type (klass->fields [1].type) == mono_defaults.boolean_class);
2085 if (*(guint8*)(buf + klass->fields [1].offset - sizeof (MonoObject))) {
2086 MonoObject *o = mono_object_new (mono_domain_get (), param_class);
2087 memcpy (mono_object_unbox (o), buf + klass->fields [0].offset - sizeof (MonoObject), mono_class_value_size (param_class, NULL));
2088 return o;
2090 else
2091 return NULL;
2095 * mono_get_delegate_invoke:
2096 * @klass: The delegate class
2098 * Returns: the MonoMethod for the "Invoke" method in the delegate klass
2100 MonoMethod *
2101 mono_get_delegate_invoke (MonoClass *klass)
2103 MonoMethod *im;
2105 im = mono_class_get_method_from_name (klass, "Invoke", -1);
2106 g_assert (im);
2108 return im;
2112 * mono_runtime_delegate_invoke:
2113 * @delegate: pointer to a delegate object.
2114 * @params: parameters for the delegate.
2115 * @exc: Pointer to the exception result.
2117 * Invokes the delegate method @delegate with the parameters provided.
2119 * You can pass NULL as the exc argument if you don't want to
2120 * catch exceptions, otherwise, *exc will be set to the exception
2121 * thrown, if any. if an exception is thrown, you can't use the
2122 * MonoObject* result from the function.
2124 MonoObject*
2125 mono_runtime_delegate_invoke (MonoObject *delegate, void **params, MonoObject **exc)
2127 MonoMethod *im;
2129 im = mono_get_delegate_invoke (delegate->vtable->klass);
2130 g_assert (im);
2132 return mono_runtime_invoke (im, delegate, params, exc);
2135 static char **main_args = NULL;
2136 static int num_main_args;
2139 * mono_runtime_get_main_args:
2141 * Returns: a MonoArray with the arguments passed to the main program
2143 MonoArray*
2144 mono_runtime_get_main_args (void)
2146 MonoArray *res;
2147 int i;
2148 MonoDomain *domain = mono_domain_get ();
2150 if (!main_args)
2151 return NULL;
2153 res = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, num_main_args);
2155 for (i = 0; i < num_main_args; ++i)
2156 mono_array_setref (res, i, mono_string_new (domain, main_args [i]));
2158 return res;
2161 static void
2162 fire_process_exit_event (void)
2164 MonoClassField *field;
2165 MonoDomain *domain = mono_domain_get ();
2166 gpointer pa [2];
2167 MonoObject *delegate, *exc;
2169 field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
2170 g_assert (field);
2172 if (domain != mono_get_root_domain ())
2173 return;
2175 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
2176 if (delegate == NULL)
2177 return;
2179 pa [0] = domain;
2180 pa [1] = NULL;
2181 mono_runtime_delegate_invoke (delegate, pa, &exc);
2185 * mono_runtime_run_main:
2186 * @method: the method to start the application with (usually Main)
2187 * @argc: number of arguments from the command line
2188 * @argv: array of strings from the command line
2189 * @exc: excetption results
2191 * Execute a standard Main() method (argc/argv contains the
2192 * executable name). This method also sets the command line argument value
2193 * needed by System.Environment.
2198 mono_runtime_run_main (MonoMethod *method, int argc, char* argv[],
2199 MonoObject **exc)
2201 int i;
2202 MonoArray *args = NULL;
2203 MonoDomain *domain = mono_domain_get ();
2204 gchar *utf8_fullpath;
2205 int result;
2207 g_assert (method != NULL);
2209 mono_thread_set_main (mono_thread_current ());
2211 main_args = g_new0 (char*, argc);
2212 num_main_args = argc;
2214 if (!g_path_is_absolute (argv [0])) {
2215 gchar *basename = g_path_get_basename (argv [0]);
2216 gchar *fullpath = g_build_filename (method->klass->image->assembly->basedir,
2217 basename,
2218 NULL);
2220 utf8_fullpath = mono_utf8_from_external (fullpath);
2221 if(utf8_fullpath == NULL) {
2222 /* Printing the arg text will cause glib to
2223 * whinge about "Invalid UTF-8", but at least
2224 * its relevant, and shows the problem text
2225 * string.
2227 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", fullpath);
2228 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2229 exit (-1);
2232 g_free (fullpath);
2233 g_free (basename);
2234 } else {
2235 utf8_fullpath = mono_utf8_from_external (argv[0]);
2236 if(utf8_fullpath == NULL) {
2237 g_print ("\nCannot determine the text encoding for the assembly location: %s\n", argv[0]);
2238 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2239 exit (-1);
2243 main_args [0] = utf8_fullpath;
2245 for (i = 1; i < argc; ++i) {
2246 gchar *utf8_arg;
2248 utf8_arg=mono_utf8_from_external (argv[i]);
2249 if(utf8_arg==NULL) {
2250 /* Ditto the comment about Invalid UTF-8 here */
2251 g_print ("\nCannot determine the text encoding for argument %d (%s).\n", i, argv[i]);
2252 g_print ("Please add the correct encoding to MONO_EXTERNAL_ENCODINGS and try again.\n");
2253 exit (-1);
2256 main_args [i] = utf8_arg;
2258 argc--;
2259 argv++;
2260 if (mono_method_signature (method)->param_count) {
2261 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
2262 for (i = 0; i < argc; ++i) {
2263 /* The encodings should all work, given that
2264 * we've checked all these args for the
2265 * main_args array.
2267 gchar *str = mono_utf8_from_external (argv [i]);
2268 MonoString *arg = mono_string_new (domain, str);
2269 mono_array_setref (args, i, arg);
2270 g_free (str);
2272 } else {
2273 args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, 0);
2276 mono_assembly_set_main (method->klass->image->assembly);
2278 result = mono_runtime_exec_main (method, args, exc);
2279 fire_process_exit_event ();
2280 return result;
2283 /* Used in mono_unhandled_exception */
2284 static MonoObject *
2285 create_unhandled_exception_eventargs (MonoObject *exc)
2287 MonoClass *klass;
2288 gpointer args [2];
2289 MonoMethod *method = NULL;
2290 MonoBoolean is_terminating = TRUE;
2291 MonoObject *obj;
2293 klass = mono_class_from_name (mono_defaults.corlib, "System", "UnhandledExceptionEventArgs");
2294 g_assert (klass);
2296 mono_class_init (klass);
2298 /* UnhandledExceptionEventArgs only has 1 public ctor with 2 args */
2299 method = mono_class_get_method_from_name_flags (klass, ".ctor", 2, METHOD_ATTRIBUTE_PUBLIC);
2300 g_assert (method);
2302 args [0] = exc;
2303 args [1] = &is_terminating;
2305 obj = mono_object_new (mono_domain_get (), klass);
2306 mono_runtime_invoke (method, obj, args, NULL);
2308 return obj;
2312 * mono_unhandled_exception:
2313 * @exc: exception thrown
2315 * This is a VM internal routine.
2317 * We call this function when we detect an unhandled exception
2318 * in the default domain.
2320 * It invokes the * UnhandledException event in AppDomain or prints
2321 * a warning to the console
2323 void
2324 mono_unhandled_exception (MonoObject *exc)
2326 MonoDomain *domain = mono_domain_get ();
2327 MonoClassField *field;
2328 MonoObject *delegate;
2330 field=mono_class_get_field_from_name(mono_defaults.appdomain_class,
2331 "UnhandledException");
2332 g_assert (field);
2334 if (exc->vtable->klass != mono_defaults.threadabortexception_class) {
2335 delegate = *(MonoObject **)(((char *)domain->domain) + field->offset);
2337 /* set exitcode only in the main thread */
2338 if (mono_thread_current () == main_thread)
2339 mono_environment_exitcode_set (1);
2340 if (domain != mono_get_root_domain () || !delegate) {
2341 mono_print_unhandled_exception (exc);
2342 } else {
2343 MonoObject *e = NULL;
2344 gpointer pa [2];
2346 pa [0] = domain->domain;
2347 pa [1] = create_unhandled_exception_eventargs (exc);
2348 mono_runtime_delegate_invoke (delegate, pa, &e);
2350 if (e) {
2351 gchar *msg = mono_string_to_utf8 (((MonoException *) e)->message);
2352 g_warning ("exception inside UnhandledException handler: %s\n", msg);
2353 g_free (msg);
2360 * Launch a new thread to execute a function
2362 * main_func is called back from the thread with main_args as the
2363 * parameter. The callback function is expected to start Main()
2364 * eventually. This function then waits for all managed threads to
2365 * finish.
2366 * It is not necesseray anymore to execute managed code in a subthread,
2367 * so this function should not be used anymore by default: just
2368 * execute the code and then call mono_thread_manage ().
2370 void
2371 mono_runtime_exec_managed_code (MonoDomain *domain,
2372 MonoMainThreadFunc main_func,
2373 gpointer main_args)
2375 mono_thread_create (domain, main_func, main_args);
2377 mono_thread_manage ();
2381 * Execute a standard Main() method (args doesn't contain the
2382 * executable name).
2385 mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
2387 MonoDomain *domain;
2388 gpointer pa [1];
2389 int rval;
2391 g_assert (args);
2393 pa [0] = args;
2395 domain = mono_object_domain (args);
2396 if (!domain->entry_assembly) {
2397 gchar *str;
2398 MonoAssembly *assembly;
2400 assembly = method->klass->image->assembly;
2401 domain->entry_assembly = assembly;
2402 MONO_OBJECT_SETREF (domain->setup, application_base, mono_string_new (domain, assembly->basedir));
2404 str = g_strconcat (assembly->image->name, ".config", NULL);
2405 MONO_OBJECT_SETREF (domain->setup, configuration_file, mono_string_new (domain, str));
2406 g_free (str);
2409 /* FIXME: check signature of method */
2410 if (mono_method_signature (method)->ret->type == MONO_TYPE_I4) {
2411 MonoObject *res;
2412 res = mono_runtime_invoke (method, NULL, pa, exc);
2413 if (!exc || !*exc)
2414 rval = *(guint32 *)((char *)res + sizeof (MonoObject));
2415 else
2416 rval = -1;
2418 mono_environment_exitcode_set (rval);
2419 } else {
2420 mono_runtime_invoke (method, NULL, pa, exc);
2421 if (!exc || !*exc)
2422 rval = 0;
2423 else {
2424 /* If the return type of Main is void, only
2425 * set the exitcode if an exception was thrown
2426 * (we don't want to blow away an
2427 * explicitly-set exit code)
2429 rval = -1;
2430 mono_environment_exitcode_set (rval);
2434 return rval;
2438 * mono_install_runtime_invoke:
2439 * @func: Function to install
2441 * This is a VM internal routine
2443 void
2444 mono_install_runtime_invoke (MonoInvokeFunc func)
2446 default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
2450 * mono_runtime_invoke_array:
2451 * @method: method to invoke
2452 * @obJ: object instance
2453 * @params: arguments to the method
2454 * @exc: exception information.
2456 * Invokes the method represented by @method on the object @obj.
2458 * obj is the 'this' pointer, it should be NULL for static
2459 * methods, a MonoObject* for object instances and a pointer to
2460 * the value type for value types.
2462 * The params array contains the arguments to the method with the
2463 * same convention: MonoObject* pointers for object instances and
2464 * pointers to the value type otherwise. The _invoke_array
2465 * variant takes a C# object[] as the params argument (MonoArray
2466 * *params): in this case the value types are boxed inside the
2467 * respective reference representation.
2469 * From unmanaged code you'll usually use the
2470 * mono_runtime_invoke() variant.
2472 * Note that this function doesn't handle virtual methods for
2473 * you, it will exec the exact method you pass: we still need to
2474 * expose a function to lookup the derived class implementation
2475 * of a virtual method (there are examples of this in the code,
2476 * though).
2478 * You can pass NULL as the exc argument if you don't want to
2479 * catch exceptions, otherwise, *exc will be set to the exception
2480 * thrown, if any. if an exception is thrown, you can't use the
2481 * MonoObject* result from the function.
2483 * If the method returns a value type, it is boxed in an object
2484 * reference.
2486 MonoObject*
2487 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
2488 MonoObject **exc)
2490 MonoMethodSignature *sig = mono_method_signature (method);
2491 gpointer *pa = NULL;
2492 int i;
2494 if (NULL != params) {
2495 pa = alloca (sizeof (gpointer) * mono_array_length (params));
2496 for (i = 0; i < mono_array_length (params); i++) {
2497 MonoType *t = sig->params [i];
2499 again:
2500 switch (t->type) {
2501 case MONO_TYPE_U1:
2502 case MONO_TYPE_I1:
2503 case MONO_TYPE_BOOLEAN:
2504 case MONO_TYPE_U2:
2505 case MONO_TYPE_I2:
2506 case MONO_TYPE_CHAR:
2507 case MONO_TYPE_U:
2508 case MONO_TYPE_I:
2509 case MONO_TYPE_U4:
2510 case MONO_TYPE_I4:
2511 case MONO_TYPE_U8:
2512 case MONO_TYPE_I8:
2513 case MONO_TYPE_R4:
2514 case MONO_TYPE_R8:
2515 case MONO_TYPE_VALUETYPE:
2516 if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type (sig->params [i]))) {
2517 if (t->byref)
2518 /* FIXME: */
2519 g_assert_not_reached ();
2520 /* The runtime invoke wrapper needs the original boxed vtype */
2521 pa [i] = (char *)(((gpointer *)params->vector)[i]);
2522 } else {
2523 /* MS seems to create the objects if a null is passed in */
2524 if (!((gpointer *)params->vector)[i])
2525 ((gpointer*)params->vector)[i] = mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i]));
2527 if (t->byref) {
2529 * We can't pass the unboxed vtype byref to the callee, since
2530 * that would mean the callee would be able to modify boxed
2531 * primitive types. So we (and MS) make a copy of the boxed
2532 * object, pass that to the callee, and replace the original
2533 * boxed object in the arg array with the copy.
2535 MonoObject *orig = mono_array_get (params, MonoObject*, i);
2536 MonoObject *copy = mono_value_box (mono_domain_get (), orig->vtable->klass, mono_object_unbox (orig));
2537 mono_array_setref (params, i, copy);
2540 pa [i] = (char *)(((gpointer *)params->vector)[i]) + sizeof (MonoObject);
2542 break;
2543 case MONO_TYPE_STRING:
2544 case MONO_TYPE_OBJECT:
2545 case MONO_TYPE_CLASS:
2546 case MONO_TYPE_ARRAY:
2547 case MONO_TYPE_SZARRAY:
2548 if (t->byref)
2549 pa [i] = &(((gpointer *)params->vector)[i]);
2550 else
2551 pa [i] = (char *)(((gpointer *)params->vector)[i]);
2552 break;
2553 case MONO_TYPE_GENERICINST:
2554 t = &t->data.generic_class->container_class->byval_arg;
2555 goto again;
2556 default:
2557 g_error ("type 0x%x not handled in ves_icall_InternalInvoke", sig->params [i]->type);
2562 if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
2563 void *o = obj;
2565 if (mono_class_is_nullable (method->klass)) {
2566 /* Need to create a boxed vtype instead */
2567 g_assert (!obj);
2569 if (!params)
2570 return NULL;
2571 else
2572 return mono_value_box (mono_domain_get (), method->klass->cast_class, pa [0]);
2575 if (!obj) {
2576 obj = mono_object_new (mono_domain_get (), method->klass);
2577 if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
2578 method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
2580 if (method->klass->valuetype)
2581 o = mono_object_unbox (obj);
2582 else
2583 o = obj;
2585 else if (method->klass->valuetype)
2586 obj = mono_value_box (mono_domain_get (), method->klass, obj);
2588 mono_runtime_invoke (method, o, pa, exc);
2589 return obj;
2590 } else {
2591 /* obj must be already unboxed if needed */
2592 return mono_runtime_invoke (method, obj, pa, exc);
2596 static void
2597 arith_overflow (void)
2599 mono_raise_exception (mono_get_exception_overflow ());
2603 * mono_object_allocate:
2604 * @size: number of bytes to allocate
2606 * This is a very simplistic routine until we have our GC-aware
2607 * memory allocator.
2609 * Returns: an allocated object of size @size, or NULL on failure.
2611 static inline void *
2612 mono_object_allocate (size_t size, MonoVTable *vtable)
2614 MonoObject *o;
2615 mono_stats.new_object_count++;
2616 ALLOC_OBJECT (o, vtable, size);
2618 return o;
2622 * mono_object_allocate_ptrfree:
2623 * @size: number of bytes to allocate
2625 * Note that the memory allocated is not zeroed.
2626 * Returns: an allocated object of size @size, or NULL on failure.
2628 static inline void *
2629 mono_object_allocate_ptrfree (size_t size, MonoVTable *vtable)
2631 MonoObject *o;
2632 mono_stats.new_object_count++;
2633 ALLOC_PTRFREE (o, vtable, size);
2634 return o;
2637 static inline void *
2638 mono_object_allocate_spec (size_t size, MonoVTable *vtable)
2640 void *o;
2641 ALLOC_TYPED (o, size, vtable);
2642 mono_stats.new_object_count++;
2644 return o;
2648 * mono_object_new:
2649 * @klass: the class of the object that we want to create
2651 * Returns: a newly created object whose definition is
2652 * looked up using @klass. This will not invoke any constructors,
2653 * so the consumer of this routine has to invoke any constructors on
2654 * its own to initialize the object.
2656 MonoObject *
2657 mono_object_new (MonoDomain *domain, MonoClass *klass)
2659 MONO_ARCH_SAVE_REGS;
2660 return mono_object_new_specific (mono_class_vtable (domain, klass));
2664 * mono_object_new_specific:
2665 * @vtable: the vtable of the object that we want to create
2667 * Returns: A newly created object with class and domain specified
2668 * by @vtable
2670 MonoObject *
2671 mono_object_new_specific (MonoVTable *vtable)
2673 MonoObject *o;
2675 MONO_ARCH_SAVE_REGS;
2677 /* check for is_com_object for COM Interop */
2678 if (vtable->remote || vtable->klass->is_com_object)
2680 gpointer pa [1];
2681 MonoMethod *im = vtable->domain->create_proxy_for_type_method;
2683 if (im == NULL) {
2684 MonoClass *klass = mono_class_from_name (mono_defaults.corlib, "System.Runtime.Remoting.Activation", "ActivationServices");
2686 if (!klass->inited)
2687 mono_class_init (klass);
2689 im = mono_class_get_method_from_name (klass, "CreateProxyForType", 1);
2690 g_assert (im);
2691 vtable->domain->create_proxy_for_type_method = im;
2694 pa [0] = mono_type_get_object (mono_domain_get (), &vtable->klass->byval_arg);
2696 o = mono_runtime_invoke (im, NULL, pa, NULL);
2697 if (o != NULL) return o;
2700 return mono_object_new_alloc_specific (vtable);
2703 MonoObject *
2704 mono_object_new_alloc_specific (MonoVTable *vtable)
2706 MonoObject *o;
2708 if (!vtable->klass->has_references) {
2709 o = mono_object_new_ptrfree (vtable);
2710 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2711 o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
2712 } else {
2713 /* printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
2714 o = mono_object_allocate (vtable->klass->instance_size, vtable);
2716 if (vtable->klass->has_finalize)
2717 mono_object_register_finalizer (o);
2719 mono_profiler_allocation (o, vtable->klass);
2720 return o;
2723 MonoObject*
2724 mono_object_new_fast (MonoVTable *vtable)
2726 MonoObject *o;
2727 ALLOC_TYPED (o, vtable->klass->instance_size, vtable);
2728 return o;
2731 static MonoObject*
2732 mono_object_new_ptrfree (MonoVTable *vtable)
2734 MonoObject *obj;
2735 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
2736 #if NEED_TO_ZERO_PTRFREE
2737 /* an inline memset is much faster for the common vcase of small objects
2738 * note we assume the allocated size is a multiple of sizeof (void*).
2740 if (vtable->klass->instance_size < 128) {
2741 gpointer *p, *end;
2742 end = (gpointer*)((char*)obj + vtable->klass->instance_size);
2743 p = (gpointer*)((char*)obj + sizeof (MonoObject));
2744 while (p < end) {
2745 *p = NULL;
2746 ++p;
2748 } else {
2749 memset ((char*)obj + sizeof (MonoObject), 0, vtable->klass->instance_size - sizeof (MonoObject));
2751 #endif
2752 return obj;
2755 static MonoObject*
2756 mono_object_new_ptrfree_box (MonoVTable *vtable)
2758 MonoObject *obj;
2759 ALLOC_PTRFREE (obj, vtable, vtable->klass->instance_size);
2760 /* the object will be boxed right away, no need to memzero it */
2761 return obj;
2765 * mono_class_get_allocation_ftn:
2766 * @vtable: vtable
2767 * @for_box: the object will be used for boxing
2768 * @pass_size_in_words:
2770 * Return the allocation function appropriate for the given class.
2773 void*
2774 mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *pass_size_in_words)
2776 *pass_size_in_words = FALSE;
2778 if (vtable->klass->has_finalize || vtable->klass->marshalbyref || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
2779 return mono_object_new_specific;
2781 if (!vtable->klass->has_references) {
2782 //g_print ("ptrfree for %s.%s\n", vtable->klass->name_space, vtable->klass->name);
2783 if (for_box)
2784 return mono_object_new_ptrfree_box;
2785 return mono_object_new_ptrfree;
2788 if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
2790 return mono_object_new_fast;
2793 * FIXME: This is actually slower than mono_object_new_fast, because
2794 * of the overhead of parameter passing.
2797 *pass_size_in_words = TRUE;
2798 #ifdef GC_REDIRECT_TO_LOCAL
2799 return GC_local_gcj_fast_malloc;
2800 #else
2801 return GC_gcj_fast_malloc;
2802 #endif
2806 return mono_object_new_specific;
2810 * mono_object_new_from_token:
2811 * @image: Context where the type_token is hosted
2812 * @token: a token of the type that we want to create
2814 * Returns: A newly created object whose definition is
2815 * looked up using @token in the @image image
2817 MonoObject *
2818 mono_object_new_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
2820 MonoClass *class;
2822 class = mono_class_get (image, token);
2824 return mono_object_new (domain, class);
2829 * mono_object_clone:
2830 * @obj: the object to clone
2832 * Returns: A newly created object who is a shallow copy of @obj
2834 MonoObject *
2835 mono_object_clone (MonoObject *obj)
2837 MonoObject *o;
2838 int size;
2840 size = obj->vtable->klass->instance_size;
2841 o = mono_object_allocate (size, obj->vtable);
2842 /* do not copy the sync state */
2843 memcpy ((char*)o + sizeof (MonoObject), (char*)obj + sizeof (MonoObject), size - sizeof (MonoObject));
2845 #ifdef HAVE_SGEN_GC
2846 if (obj->vtable->klass->has_references)
2847 mono_gc_wbarrier_object (o);
2848 #endif
2849 mono_profiler_allocation (o, obj->vtable->klass);
2851 if (obj->vtable->klass->has_finalize)
2852 mono_object_register_finalizer (o);
2853 return o;
2857 * mono_array_full_copy:
2858 * @src: source array to copy
2859 * @dest: destination array
2861 * Copies the content of one array to another with exactly the same type and size.
2863 void
2864 mono_array_full_copy (MonoArray *src, MonoArray *dest)
2866 int size;
2867 MonoClass *klass = src->obj.vtable->klass;
2869 MONO_ARCH_SAVE_REGS;
2871 g_assert (klass == dest->obj.vtable->klass);
2873 size = mono_array_length (src);
2874 g_assert (size == mono_array_length (dest));
2875 size *= mono_array_element_size (klass);
2876 #ifdef HAVE_SGEN_GC
2877 if (klass->valuetype) {
2878 if (klass->has_references)
2879 mono_value_copy_array (dest, 0, src, mono_array_length (src));
2880 else
2881 memcpy (&dest->vector, &src->vector, size);
2882 } else {
2883 mono_array_memcpy_refs (dest, 0, src, 0, mono_array_length (src));
2885 #else
2886 memcpy (&dest->vector, &src->vector, size);
2887 #endif
2891 * mono_array_clone_in_domain:
2892 * @domain: the domain in which the array will be cloned into
2893 * @array: the array to clone
2895 * This routine returns a copy of the array that is hosted on the
2896 * specified MonoDomain.
2898 MonoArray*
2899 mono_array_clone_in_domain (MonoDomain *domain, MonoArray *array)
2901 MonoArray *o;
2902 guint32 size, i;
2903 guint32 *sizes;
2904 MonoClass *klass = array->obj.vtable->klass;
2906 MONO_ARCH_SAVE_REGS;
2908 if (array->bounds == NULL) {
2909 size = mono_array_length (array);
2910 o = mono_array_new_full (domain, klass, &size, NULL);
2912 size *= mono_array_element_size (klass);
2913 #ifdef HAVE_SGEN_GC
2914 if (klass->valuetype) {
2915 if (klass->has_references)
2916 mono_value_copy_array (o, 0, array, mono_array_length (array));
2917 else
2918 memcpy (&o->vector, &array->vector, size);
2919 } else {
2920 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
2922 #else
2923 memcpy (&o->vector, &array->vector, size);
2924 #endif
2925 return o;
2928 sizes = alloca (klass->rank * sizeof(guint32) * 2);
2929 size = mono_array_element_size (klass);
2930 for (i = 0; i < klass->rank; ++i) {
2931 sizes [i] = array->bounds [i].length;
2932 size *= array->bounds [i].length;
2933 sizes [i + klass->rank] = array->bounds [i].lower_bound;
2935 o = mono_array_new_full (domain, klass, sizes, sizes + klass->rank);
2936 #ifdef HAVE_SGEN_GC
2937 if (klass->valuetype) {
2938 if (klass->has_references)
2939 mono_value_copy_array (o, 0, array, mono_array_length (array));
2940 else
2941 memcpy (&o->vector, &array->vector, size);
2942 } else {
2943 mono_array_memcpy_refs (o, 0, array, 0, mono_array_length (array));
2945 #else
2946 memcpy (&o->vector, &array->vector, size);
2947 #endif
2949 return o;
2953 * mono_array_clone:
2954 * @array: the array to clone
2956 * Returns: A newly created array who is a shallow copy of @array
2958 MonoArray*
2959 mono_array_clone (MonoArray *array)
2961 return mono_array_clone_in_domain (((MonoObject *)array)->vtable->domain, array);
2964 /* helper macros to check for overflow when calculating the size of arrays */
2965 #define MYGUINT32_MAX 4294967295U
2966 #define CHECK_ADD_OVERFLOW_UN(a,b) \
2967 (guint32)(MYGUINT32_MAX) - (guint32)(b) < (guint32)(a) ? -1 : 0
2968 #define CHECK_MUL_OVERFLOW_UN(a,b) \
2969 ((guint32)(a) == 0) || ((guint32)(b) == 0) ? 0 : \
2970 (guint32)(b) > ((MYGUINT32_MAX) / (guint32)(a))
2973 * mono_array_new_full:
2974 * @domain: domain where the object is created
2975 * @array_class: array class
2976 * @lengths: lengths for each dimension in the array
2977 * @lower_bounds: lower bounds for each dimension in the array (may be NULL)
2979 * This routine creates a new array objects with the given dimensions,
2980 * lower bounds and type.
2982 MonoArray*
2983 mono_array_new_full (MonoDomain *domain, MonoClass *array_class, guint32 *lengths, guint32 *lower_bounds)
2985 guint32 byte_len, len, bounds_size;
2986 MonoObject *o;
2987 MonoArray *array;
2988 MonoVTable *vtable;
2989 int i;
2991 if (!array_class->inited)
2992 mono_class_init (array_class);
2994 byte_len = mono_array_element_size (array_class);
2995 len = 1;
2997 /* A single dimensional array with a 0 lower bound is the same as an szarray */
2998 if (array_class->rank == 1 && ((array_class->byval_arg.type == MONO_TYPE_SZARRAY) || (lower_bounds && lower_bounds [0] == 0))) {
2999 len = lengths [0];
3000 if ((int) len < 0)
3001 arith_overflow ();
3002 bounds_size = 0;
3003 } else {
3004 bounds_size = sizeof (MonoArrayBounds) * array_class->rank;
3006 for (i = 0; i < array_class->rank; ++i) {
3007 if ((int) lengths [i] < 0)
3008 arith_overflow ();
3009 if (CHECK_MUL_OVERFLOW_UN (len, lengths [i]))
3010 mono_gc_out_of_memory (MYGUINT32_MAX);
3011 len *= lengths [i];
3015 if (CHECK_MUL_OVERFLOW_UN (byte_len, len))
3016 mono_gc_out_of_memory (MYGUINT32_MAX);
3017 byte_len *= len;
3018 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
3019 mono_gc_out_of_memory (MYGUINT32_MAX);
3020 byte_len += sizeof (MonoArray);
3021 if (bounds_size) {
3022 /* align */
3023 if (CHECK_ADD_OVERFLOW_UN (byte_len, 3))
3024 mono_gc_out_of_memory (MYGUINT32_MAX);
3025 byte_len = (byte_len + 3) & ~3;
3026 if (CHECK_ADD_OVERFLOW_UN (byte_len, bounds_size))
3027 mono_gc_out_of_memory (MYGUINT32_MAX);
3028 byte_len += bounds_size;
3031 * Following three lines almost taken from mono_object_new ():
3032 * they need to be kept in sync.
3034 vtable = mono_class_vtable (domain, array_class);
3035 if (!array_class->has_references) {
3036 o = mono_object_allocate_ptrfree (byte_len, vtable);
3037 #if NEED_TO_ZERO_PTRFREE
3038 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
3039 #endif
3040 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3041 o = mono_object_allocate_spec (byte_len, vtable);
3042 }else {
3043 o = mono_object_allocate (byte_len, vtable);
3046 array = (MonoArray*)o;
3047 array->max_length = len;
3049 if (bounds_size) {
3050 MonoArrayBounds *bounds = (MonoArrayBounds*)((char*)array + byte_len - bounds_size);
3051 array->bounds = bounds;
3052 for (i = 0; i < array_class->rank; ++i) {
3053 bounds [i].length = lengths [i];
3054 if (lower_bounds)
3055 bounds [i].lower_bound = lower_bounds [i];
3059 mono_profiler_allocation (o, array_class);
3061 return array;
3065 * mono_array_new:
3066 * @domain: domain where the object is created
3067 * @eclass: element class
3068 * @n: number of array elements
3070 * This routine creates a new szarray with @n elements of type @eclass.
3072 MonoArray *
3073 mono_array_new (MonoDomain *domain, MonoClass *eclass, guint32 n)
3075 MonoClass *ac;
3077 MONO_ARCH_SAVE_REGS;
3079 ac = mono_array_class_get (eclass, 1);
3080 g_assert (ac != NULL);
3082 return mono_array_new_specific (mono_class_vtable (domain, ac), n);
3086 * mono_array_new_specific:
3087 * @vtable: a vtable in the appropriate domain for an initialized class
3088 * @n: number of array elements
3090 * This routine is a fast alternative to mono_array_new() for code which
3091 * can be sure about the domain it operates in.
3093 MonoArray *
3094 mono_array_new_specific (MonoVTable *vtable, guint32 n)
3096 MonoObject *o;
3097 MonoArray *ao;
3098 guint32 byte_len, elem_size;
3100 MONO_ARCH_SAVE_REGS;
3102 if ((int) n < 0)
3103 arith_overflow ();
3105 elem_size = mono_array_element_size (vtable->klass);
3106 if (CHECK_MUL_OVERFLOW_UN (n, elem_size))
3107 mono_gc_out_of_memory (MYGUINT32_MAX);
3108 byte_len = n * elem_size;
3109 if (CHECK_ADD_OVERFLOW_UN (byte_len, sizeof (MonoArray)))
3110 mono_gc_out_of_memory (MYGUINT32_MAX);
3111 byte_len += sizeof (MonoArray);
3112 if (!vtable->klass->has_references) {
3113 o = mono_object_allocate_ptrfree (byte_len, vtable);
3114 #if NEED_TO_ZERO_PTRFREE
3115 memset ((char*)o + sizeof (MonoObject), 0, byte_len - sizeof (MonoObject));
3116 #endif
3117 } else if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
3118 o = mono_object_allocate_spec (byte_len, vtable);
3119 } else {
3120 /* printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
3121 o = mono_object_allocate (byte_len, vtable);
3124 ao = (MonoArray *)o;
3125 ao->bounds = NULL;
3126 ao->max_length = n;
3127 mono_profiler_allocation (o, vtable->klass);
3129 return ao;
3133 * mono_string_new_utf16:
3134 * @text: a pointer to an utf16 string
3135 * @len: the length of the string
3137 * Returns: A newly created string object which contains @text.
3139 MonoString *
3140 mono_string_new_utf16 (MonoDomain *domain, const guint16 *text, gint32 len)
3142 MonoString *s;
3144 s = mono_string_new_size (domain, len);
3145 g_assert (s != NULL);
3147 memcpy (mono_string_chars (s), text, len * 2);
3149 return s;
3153 * mono_string_new_size:
3154 * @text: a pointer to an utf16 string
3155 * @len: the length of the string
3157 * Returns: A newly created string object of @len
3159 MonoString *
3160 mono_string_new_size (MonoDomain *domain, gint32 len)
3162 MonoString *s;
3163 MonoVTable *vtable;
3164 size_t size = (sizeof (MonoString) + ((len + 1) * 2));
3166 /* overflow ? can't fit it, can't allocate it! */
3167 if (len > size)
3168 mono_gc_out_of_memory (-1);
3170 vtable = mono_class_vtable (domain, mono_defaults.string_class);
3172 s = mono_object_allocate_ptrfree (size, vtable);
3174 s->length = len;
3175 #if NEED_TO_ZERO_PTRFREE
3176 s->chars [len] = 0;
3177 #endif
3178 mono_profiler_allocation ((MonoObject*)s, mono_defaults.string_class);
3180 return s;
3184 * mono_string_new_len:
3185 * @text: a pointer to an utf8 string
3186 * @length: number of bytes in @text to consider
3188 * Returns: A newly created string object which contains @text.
3190 MonoString*
3191 mono_string_new_len (MonoDomain *domain, const char *text, guint length)
3193 GError *error = NULL;
3194 MonoString *o = NULL;
3195 guint16 *ut;
3196 glong items_written;
3198 ut = g_utf8_to_utf16 (text, length, NULL, &items_written, &error);
3200 if (!error)
3201 o = mono_string_new_utf16 (domain, ut, items_written);
3202 else
3203 g_error_free (error);
3205 g_free (ut);
3207 return o;
3211 * mono_string_new:
3212 * @text: a pointer to an utf8 string
3214 * Returns: A newly created string object which contains @text.
3216 MonoString*
3217 mono_string_new (MonoDomain *domain, const char *text)
3219 GError *error = NULL;
3220 MonoString *o = NULL;
3221 guint16 *ut;
3222 glong items_written;
3223 int l;
3225 l = strlen (text);
3227 ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
3229 if (!error)
3230 o = mono_string_new_utf16 (domain, ut, items_written);
3231 else
3232 g_error_free (error);
3234 g_free (ut);
3236 return o;
3240 * mono_string_new_wrapper:
3241 * @text: pointer to utf8 characters.
3243 * Helper function to create a string object from @text in the current domain.
3245 MonoString*
3246 mono_string_new_wrapper (const char *text)
3248 MonoDomain *domain = mono_domain_get ();
3250 MONO_ARCH_SAVE_REGS;
3252 if (text)
3253 return mono_string_new (domain, text);
3255 return NULL;
3259 * mono_value_box:
3260 * @class: the class of the value
3261 * @value: a pointer to the unboxed data
3263 * Returns: A newly created object which contains @value.
3265 MonoObject *
3266 mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
3268 MonoObject *res;
3269 int size;
3270 MonoVTable *vtable;
3272 g_assert (class->valuetype);
3274 vtable = mono_class_vtable (domain, class);
3275 size = mono_class_instance_size (class);
3276 res = mono_object_allocate (size, vtable);
3277 mono_profiler_allocation (res, class);
3279 size = size - sizeof (MonoObject);
3281 #ifdef HAVE_SGEN_GC
3282 mono_gc_wbarrier_value_copy ((char *)res + sizeof (MonoObject), value, 1, class);
3283 #endif
3285 #if NO_UNALIGNED_ACCESS
3286 memcpy ((char *)res + sizeof (MonoObject), value, size);
3287 #else
3288 switch (size) {
3289 case 1:
3290 *((guint8 *) res + sizeof (MonoObject)) = *(guint8 *) value;
3291 break;
3292 case 2:
3293 *(guint16 *)((guint8 *) res + sizeof (MonoObject)) = *(guint16 *) value;
3294 break;
3295 case 4:
3296 *(guint32 *)((guint8 *) res + sizeof (MonoObject)) = *(guint32 *) value;
3297 break;
3298 case 8:
3299 *(guint64 *)((guint8 *) res + sizeof (MonoObject)) = *(guint64 *) value;
3300 break;
3301 default:
3302 memcpy ((char *)res + sizeof (MonoObject), value, size);
3304 #endif
3305 if (class->has_finalize)
3306 mono_object_register_finalizer (res);
3307 return res;
3311 * mono_value_copy:
3312 * @dest: destination pointer
3313 * @src: source pointer
3314 * @klass: a valuetype class
3316 * Copy a valuetype from @src to @dest. This function must be used
3317 * when @klass contains references fields.
3319 void
3320 mono_value_copy (gpointer dest, gpointer src, MonoClass *klass)
3322 int size = mono_class_value_size (klass, NULL);
3323 mono_gc_wbarrier_value_copy (dest, src, 1, klass);
3324 memcpy (dest, src, size);
3328 * mono_value_copy_array:
3329 * @dest: destination array
3330 * @dest_idx: index in the @dest array
3331 * @src: source pointer
3332 * @count: number of items
3334 * Copy @count valuetype items from @src to @dest. This function must be used
3335 * when @klass contains references fields.
3336 * Overlap is handled.
3338 void
3339 mono_value_copy_array (MonoArray *dest, int dest_idx, gpointer src, int count)
3341 int size = mono_array_element_size (dest->obj.vtable->klass);
3342 char *d = mono_array_addr_with_size (dest, size, dest_idx);
3343 mono_gc_wbarrier_value_copy (d, src, count, mono_object_class (dest)->element_class);
3344 memmove (d, src, size * count);
3348 * mono_object_get_domain:
3349 * @obj: object to query
3351 * Returns: the MonoDomain where the object is hosted
3353 MonoDomain*
3354 mono_object_get_domain (MonoObject *obj)
3356 return mono_object_domain (obj);
3360 * mono_object_get_class:
3361 * @obj: object to query
3363 * Returns: the MonOClass of the object.
3365 MonoClass*
3366 mono_object_get_class (MonoObject *obj)
3368 return mono_object_class (obj);
3371 * mono_object_get_size:
3372 * @o: object to query
3374 * Returns: the size, in bytes, of @o
3376 guint
3377 mono_object_get_size (MonoObject* o)
3379 MonoClass* klass = mono_object_class (o);
3380 if (klass == mono_defaults.string_class) {
3381 return sizeof (MonoString) + 2 * mono_string_length ((MonoString*) o) + 2;
3382 } else if (o->vtable->rank) {
3383 MonoArray *array = (MonoArray*)o;
3384 size_t size = sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length (array);
3385 if (array->bounds) {
3386 size += 3;
3387 size &= ~3;
3388 size += sizeof (MonoArrayBounds) * o->vtable->rank;
3390 return size;
3391 } else {
3392 return mono_class_instance_size (klass);
3397 * mono_object_unbox:
3398 * @obj: object to unbox
3400 * Returns: a pointer to the start of the valuetype boxed in this
3401 * object.
3403 * This method will assert if the object passed is not a valuetype.
3405 gpointer
3406 mono_object_unbox (MonoObject *obj)
3408 /* add assert for valuetypes? */
3409 g_assert (obj->vtable->klass->valuetype);
3410 return ((char*)obj) + sizeof (MonoObject);
3414 * mono_object_isinst:
3415 * @obj: an object
3416 * @klass: a pointer to a class
3418 * Returns: @obj if @obj is derived from @klass
3420 MonoObject *
3421 mono_object_isinst (MonoObject *obj, MonoClass *klass)
3423 if (!klass->inited)
3424 mono_class_init (klass);
3426 if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)
3427 return mono_object_isinst_mbyref (obj, klass);
3429 if (!obj)
3430 return NULL;
3432 return mono_class_is_assignable_from (klass, obj->vtable->klass) ? obj : NULL;
3435 MonoObject *
3436 mono_object_isinst_mbyref (MonoObject *obj, MonoClass *klass)
3438 MonoVTable *vt;
3440 if (!obj)
3441 return NULL;
3443 vt = obj->vtable;
3445 if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
3446 if (klass->interface_id <= vt->max_interface_id) {
3447 /* the interface_offsets array is stored before the vtable */
3448 gpointer *interface_offsets = (gpointer*)vt;
3449 if (interface_offsets [- (klass->interface_id + 1)] != NULL)
3450 return obj;
3452 } else {
3453 MonoClass *oklass = vt->klass;
3454 if ((oklass == mono_defaults.transparent_proxy_class))
3455 oklass = ((MonoTransparentProxy *)obj)->remote_class->proxy_class;
3457 if ((oklass->idepth >= klass->idepth) && (oklass->supertypes [klass->idepth - 1] == klass))
3458 return obj;
3461 if (vt->klass == mono_defaults.transparent_proxy_class && ((MonoTransparentProxy *)obj)->custom_type_info)
3463 MonoDomain *domain = mono_domain_get ();
3464 MonoObject *res;
3465 MonoObject *rp = (MonoObject *)((MonoTransparentProxy *)obj)->rp;
3466 MonoClass *rpklass = mono_defaults.iremotingtypeinfo_class;
3467 MonoMethod *im = NULL;
3468 gpointer pa [2];
3470 im = mono_class_get_method_from_name (rpklass, "CanCastTo", -1);
3471 im = mono_object_get_virtual_method (rp, im);
3472 g_assert (im);
3474 pa [0] = mono_type_get_object (domain, &klass->byval_arg);
3475 pa [1] = obj;
3477 res = mono_runtime_invoke (im, rp, pa, NULL);
3479 if (*(MonoBoolean *) mono_object_unbox(res)) {
3480 /* Update the vtable of the remote type, so it can safely cast to this new type */
3481 mono_upgrade_remote_class (domain, obj, klass);
3482 return obj;
3486 return NULL;
3490 * mono_object_castclass_mbyref:
3491 * @obj: an object
3492 * @klass: a pointer to a class
3494 * Returns: @obj if @obj is derived from @klass, throws an exception otherwise
3496 MonoObject *
3497 mono_object_castclass_mbyref (MonoObject *obj, MonoClass *klass)
3499 if (!obj) return NULL;
3500 if (mono_object_isinst_mbyref (obj, klass)) return obj;
3502 mono_raise_exception (mono_exception_from_name (mono_defaults.corlib,
3503 "System",
3504 "InvalidCastException"));
3505 return NULL;
3508 typedef struct {
3509 MonoDomain *orig_domain;
3510 MonoString *ins;
3511 MonoString *res;
3512 } LDStrInfo;
3514 static void
3515 str_lookup (MonoDomain *domain, gpointer user_data)
3517 LDStrInfo *info = user_data;
3518 if (info->res || domain == info->orig_domain)
3519 return;
3520 info->res = mono_g_hash_table_lookup (domain->ldstr_table, info->ins);
3523 #ifdef HAVE_SGEN_GC
3525 static MonoString*
3526 mono_string_get_pinned (MonoString *str)
3528 int size;
3529 MonoString *news;
3530 size = sizeof (MonoString) + 2 * (mono_string_length (str) + 1);
3531 news = mono_gc_alloc_pinned_obj (((MonoObject*)str)->vtable, size);
3532 memcpy (mono_string_chars (news), mono_string_chars (str), mono_string_length (str) * 2);
3533 news->length = mono_string_length (str);
3534 return news;
3537 #else
3538 #define mono_string_get_pinned(str) (str)
3539 #endif
3541 static MonoString*
3542 mono_string_is_interned_lookup (MonoString *str, int insert)
3544 MonoGHashTable *ldstr_table;
3545 MonoString *res;
3546 MonoDomain *domain;
3548 domain = ((MonoObject *)str)->vtable->domain;
3549 ldstr_table = domain->ldstr_table;
3550 ldstr_lock ();
3551 if ((res = mono_g_hash_table_lookup (ldstr_table, str))) {
3552 ldstr_unlock ();
3553 return res;
3555 if (insert) {
3556 str = mono_string_get_pinned (str);
3557 mono_g_hash_table_insert (ldstr_table, str, str);
3558 ldstr_unlock ();
3559 return str;
3560 } else {
3561 LDStrInfo ldstr_info;
3562 ldstr_info.orig_domain = domain;
3563 ldstr_info.ins = str;
3564 ldstr_info.res = NULL;
3566 mono_domain_foreach (str_lookup, &ldstr_info);
3567 if (ldstr_info.res) {
3569 * the string was already interned in some other domain:
3570 * intern it in the current one as well.
3572 mono_g_hash_table_insert (ldstr_table, str, str);
3573 ldstr_unlock ();
3574 return str;
3577 ldstr_unlock ();
3578 return NULL;
3582 * mono_string_is_interned:
3583 * @o: String to probe
3585 * Returns whether the string has been interned.
3587 MonoString*
3588 mono_string_is_interned (MonoString *o)
3590 return mono_string_is_interned_lookup (o, FALSE);
3594 * mono_string_intern:
3595 * @o: String to intern
3597 * Interns the string passed.
3598 * Returns: The interned string.
3600 MonoString*
3601 mono_string_intern (MonoString *str)
3603 return mono_string_is_interned_lookup (str, TRUE);
3607 * mono_ldstr:
3608 * @domain: the domain where the string will be used.
3609 * @image: a metadata context
3610 * @idx: index into the user string table.
3612 * Implementation for the ldstr opcode.
3613 * Returns: a loaded string from the @image/@idx combination.
3615 MonoString*
3616 mono_ldstr (MonoDomain *domain, MonoImage *image, guint32 idx)
3618 MONO_ARCH_SAVE_REGS;
3620 if (image->dynamic)
3621 return mono_lookup_dynamic_token (image, MONO_TOKEN_STRING | idx);
3622 else
3623 return mono_ldstr_metdata_sig (domain, mono_metadata_user_string (image, idx));
3627 * mono_ldstr_metdata_sig
3628 * @domain: the domain for the string
3629 * @sig: the signature of a metadata string
3631 * Returns: a MonoString for a string stored in the metadata
3633 static MonoString*
3634 mono_ldstr_metdata_sig (MonoDomain *domain, const char* sig)
3636 const char *str = sig;
3637 MonoString *o, *interned;
3638 size_t len2;
3640 len2 = mono_metadata_decode_blob_size (str, &str);
3641 len2 >>= 1;
3643 o = mono_string_new_utf16 (domain, (guint16*)str, len2);
3644 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
3646 int i;
3647 guint16 *p2 = (guint16*)mono_string_chars (o);
3648 for (i = 0; i < len2; ++i) {
3649 *p2 = GUINT16_FROM_LE (*p2);
3650 ++p2;
3653 #endif
3654 ldstr_lock ();
3655 if ((interned = mono_g_hash_table_lookup (domain->ldstr_table, o))) {
3656 ldstr_unlock ();
3657 /* o will get garbage collected */
3658 return interned;
3661 o = mono_string_get_pinned (o);
3662 mono_g_hash_table_insert (domain->ldstr_table, o, o);
3663 ldstr_unlock ();
3665 return o;
3669 * mono_string_to_utf8:
3670 * @s: a System.String
3672 * Return the UTF8 representation for @s.
3673 * the resulting buffer nedds to be freed with g_free().
3675 char *
3676 mono_string_to_utf8 (MonoString *s)
3678 char *as;
3679 GError *error = NULL;
3681 if (s == NULL)
3682 return NULL;
3684 if (!s->length)
3685 return g_strdup ("");
3687 as = g_utf16_to_utf8 (mono_string_chars (s), s->length, NULL, NULL, &error);
3688 if (error) {
3689 MonoException *exc = mono_get_exception_argument ("string", error->message);
3690 g_error_free (error);
3691 mono_raise_exception(exc);
3694 return as;
3698 * mono_string_to_utf16:
3699 * @s: a MonoString
3701 * Return an null-terminated array of the utf-16 chars
3702 * contained in @s. The result must be freed with g_free().
3703 * This is a temporary helper until our string implementation
3704 * is reworked to always include the null terminating char.
3706 gunichar2 *
3707 mono_string_to_utf16 (MonoString *s)
3709 char *as;
3711 if (s == NULL)
3712 return NULL;
3714 as = g_malloc ((s->length * 2) + 2);
3715 as [(s->length * 2)] = '\0';
3716 as [(s->length * 2) + 1] = '\0';
3718 if (!s->length) {
3719 return (gunichar2 *)(as);
3722 memcpy (as, mono_string_chars(s), s->length * 2);
3723 return (gunichar2 *)(as);
3727 * mono_string_from_utf16:
3728 * @data: the UTF16 string (LPWSTR) to convert
3730 * Converts a NULL terminated UTF16 string (LPWSTR) to a MonoString.
3732 * Returns: a MonoString.
3734 MonoString *
3735 mono_string_from_utf16 (gunichar2 *data)
3737 MonoDomain *domain = mono_domain_get ();
3738 int len = 0;
3740 if (!data)
3741 return NULL;
3743 while (data [len]) len++;
3745 return mono_string_new_utf16 (domain, data, len);
3749 * mono_string_to_utf8_mp:
3750 * @s: a System.String
3752 * Same as mono_string_to_utf8, but allocate the string from a mempool.
3754 char *
3755 mono_string_to_utf8_mp (MonoMemPool *mp, MonoString *s)
3757 char *r = mono_string_to_utf8 (s);
3758 char *mp_s;
3759 int len;
3761 if (!r)
3762 return NULL;
3764 len = strlen (r) + 1;
3765 mp_s = mono_mempool_alloc (mp, len);
3766 memcpy (mp_s, r, len);
3768 g_free (r);
3770 return mp_s;
3773 static void
3774 default_ex_handler (MonoException *ex)
3776 MonoObject *o = (MonoObject*)ex;
3777 g_error ("Exception %s.%s raised in C code", o->vtable->klass->name_space, o->vtable->klass->name);
3778 exit (1);
3781 static MonoExceptionFunc ex_handler = default_ex_handler;
3784 * mono_install_handler:
3785 * @func: exception handler
3787 * This is an internal JIT routine used to install the handler for exceptions
3788 * being throwh.
3790 void
3791 mono_install_handler (MonoExceptionFunc func)
3793 ex_handler = func? func: default_ex_handler;
3797 * mono_raise_exception:
3798 * @ex: exception object
3800 * Signal the runtime that the exception @ex has been raised in unmanaged code.
3802 void
3803 mono_raise_exception (MonoException *ex)
3806 * NOTE: Do NOT annotate this function with G_GNUC_NORETURN, since
3807 * that will cause gcc to omit the function epilog, causing problems when
3808 * the JIT tries to walk the stack, since the return address on the stack
3809 * will point into the next function in the executable, not this one.
3812 if (((MonoObject*)ex)->vtable->klass == mono_defaults.threadabortexception_class)
3813 MONO_OBJECT_SETREF (mono_thread_current (), abort_exc, ex);
3815 ex_handler (ex);
3819 * mono_wait_handle_new:
3820 * @domain: Domain where the object will be created
3821 * @handle: Handle for the wait handle
3823 * Returns: A new MonoWaitHandle created in the given domain for the given handle
3825 MonoWaitHandle *
3826 mono_wait_handle_new (MonoDomain *domain, HANDLE handle)
3828 MonoWaitHandle *res;
3829 gpointer params [1];
3830 static MonoMethod *handle_set;
3832 res = (MonoWaitHandle *)mono_object_new (domain, mono_defaults.waithandle_class);
3834 /* Even though this method is virtual, it's safe to invoke directly, since the object type matches. */
3835 if (!handle_set)
3836 handle_set = mono_class_get_property_from_name (mono_defaults.waithandle_class, "Handle")->set;
3838 params [0] = &handle;
3839 mono_runtime_invoke (handle_set, res, params, NULL);
3841 return res;
3844 HANDLE
3845 mono_wait_handle_get_handle (MonoWaitHandle *handle)
3847 static MonoClassField *f_os_handle;
3848 static MonoClassField *f_safe_handle;
3850 if (!f_os_handle && !f_safe_handle) {
3851 f_os_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "os_handle");
3852 f_safe_handle = mono_class_get_field_from_name (mono_defaults.waithandle_class, "safe_wait_handle");
3855 if (f_os_handle) {
3856 HANDLE retval;
3857 mono_field_get_value ((MonoObject*)handle, f_os_handle, &retval);
3858 return retval;
3859 } else {
3860 MonoSafeHandle *sh;
3861 mono_field_get_value ((MonoObject*)handle, f_safe_handle, &sh);
3862 return sh->handle;
3867 * mono_async_result_new:
3868 * @domain:domain where the object will be created.
3869 * @handle: wait handle.
3870 * @state: state to pass to AsyncResult
3871 * @data: C closure data.
3873 * Creates a new MonoAsyncResult (AsyncResult C# class) in the given domain.
3874 * If the handle is not null, the handle is initialized to a MonOWaitHandle.
3877 MonoAsyncResult *
3878 mono_async_result_new (MonoDomain *domain, HANDLE handle, MonoObject *state, gpointer data, MonoObject *object_data)
3880 MonoAsyncResult *res = (MonoAsyncResult *)mono_object_new (domain, mono_defaults.asyncresult_class);
3881 MonoMethod *method = mono_get_context_capture_method ();
3883 /* we must capture the execution context from the original thread */
3884 if (method) {
3885 MONO_OBJECT_SETREF (res, execution_context, mono_runtime_invoke (method, NULL, NULL, NULL));
3886 /* note: result may be null if the flow is suppressed */
3889 res->data = data;
3890 MONO_OBJECT_SETREF (res, object_data, object_data);
3891 MONO_OBJECT_SETREF (res, async_state, state);
3892 if (handle != NULL)
3893 MONO_OBJECT_SETREF (res, handle, (MonoObject *) mono_wait_handle_new (domain, handle));
3895 res->sync_completed = FALSE;
3896 res->completed = FALSE;
3898 return res;
3901 void
3902 mono_message_init (MonoDomain *domain,
3903 MonoMethodMessage *this,
3904 MonoReflectionMethod *method,
3905 MonoArray *out_args)
3907 MonoMethodSignature *sig = mono_method_signature (method->method);
3908 MonoString *name;
3909 int i, j;
3910 char **names;
3911 guint8 arg_type;
3913 MONO_OBJECT_SETREF (this, method, method);
3915 MONO_OBJECT_SETREF (this, args, mono_array_new (domain, mono_defaults.object_class, sig->param_count));
3916 MONO_OBJECT_SETREF (this, arg_types, mono_array_new (domain, mono_defaults.byte_class, sig->param_count));
3917 this->async_result = NULL;
3918 this->call_type = CallType_Sync;
3920 names = g_new (char *, sig->param_count);
3921 mono_method_get_param_names (method->method, (const char **) names);
3922 MONO_OBJECT_SETREF (this, names, mono_array_new (domain, mono_defaults.string_class, sig->param_count));
3924 for (i = 0; i < sig->param_count; i++) {
3925 name = mono_string_new (domain, names [i]);
3926 mono_array_setref (this->names, i, name);
3929 g_free (names);
3930 for (i = 0, j = 0; i < sig->param_count; i++) {
3932 if (sig->params [i]->byref) {
3933 if (out_args) {
3934 MonoObject* arg = mono_array_get (out_args, gpointer, j);
3935 mono_array_setref (this->args, i, arg);
3936 j++;
3938 arg_type = 2;
3939 if (!(sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT))
3940 arg_type |= 1;
3941 } else {
3942 arg_type = 1;
3943 if (sig->params [i]->attrs & PARAM_ATTRIBUTE_OUT)
3944 arg_type |= 4;
3946 mono_array_set (this->arg_types, guint8, i, arg_type);
3951 * mono_remoting_invoke:
3952 * @real_proxy: pointer to a RealProxy object
3953 * @msg: The MonoMethodMessage to execute
3954 * @exc: used to store exceptions
3955 * @out_args: used to store output arguments
3957 * This is used to call RealProxy::Invoke(). RealProxy::Invoke() returns an
3958 * IMessage interface and it is not trivial to extract results from there. So
3959 * we call an helper method PrivateInvoke instead of calling
3960 * RealProxy::Invoke() directly.
3962 * Returns: the result object.
3964 MonoObject *
3965 mono_remoting_invoke (MonoObject *real_proxy, MonoMethodMessage *msg,
3966 MonoObject **exc, MonoArray **out_args)
3968 MonoMethod *im = real_proxy->vtable->domain->private_invoke_method;
3969 gpointer pa [4];
3971 /*static MonoObject *(*invoke) (gpointer, gpointer, MonoObject **, MonoArray **) = NULL;*/
3973 if (!im) {
3974 im = mono_class_get_method_from_name (mono_defaults.real_proxy_class, "PrivateInvoke", 4);
3975 g_assert (im);
3976 real_proxy->vtable->domain->private_invoke_method = im;
3979 pa [0] = real_proxy;
3980 pa [1] = msg;
3981 pa [2] = exc;
3982 pa [3] = out_args;
3984 return mono_runtime_invoke (im, NULL, pa, exc);
3987 MonoObject *
3988 mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
3989 MonoObject **exc, MonoArray **out_args)
3991 MonoDomain *domain;
3992 MonoMethod *method;
3993 MonoMethodSignature *sig;
3994 MonoObject *ret;
3995 int i, j, outarg_count = 0;
3997 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
3999 MonoTransparentProxy* tp = (MonoTransparentProxy *)target;
4000 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4001 target = tp->rp->unwrapped_server;
4002 } else {
4003 return mono_remoting_invoke ((MonoObject *)tp->rp, msg, exc, out_args);
4007 domain = mono_domain_get ();
4008 method = msg->method->method;
4009 sig = mono_method_signature (method);
4011 for (i = 0; i < sig->param_count; i++) {
4012 if (sig->params [i]->byref)
4013 outarg_count++;
4016 /* FIXME: GC ensure we insert a write barrier for out_args, maybe in the caller? */
4017 *out_args = mono_array_new (domain, mono_defaults.object_class, outarg_count);
4018 *exc = NULL;
4020 ret = mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
4022 for (i = 0, j = 0; i < sig->param_count; i++) {
4023 if (sig->params [i]->byref) {
4024 MonoObject* arg;
4025 arg = mono_array_get (msg->args, gpointer, i);
4026 mono_array_setref (*out_args, j, arg);
4027 j++;
4031 return ret;
4035 * mono_print_unhandled_exception:
4036 * @exc: The exception
4038 * Prints the unhandled exception.
4040 void
4041 mono_print_unhandled_exception (MonoObject *exc)
4043 char *message = (char *) "";
4044 MonoString *str;
4045 MonoMethod *method;
4046 MonoClass *klass;
4047 gboolean free_message = FALSE;
4049 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
4050 klass = exc->vtable->klass;
4051 method = NULL;
4052 while (klass && method == NULL) {
4053 method = mono_class_get_method_from_name_flags (klass, "ToString", 0, METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_PUBLIC);
4054 if (method == NULL)
4055 klass = klass->parent;
4058 g_assert (method);
4060 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
4061 if (str) {
4062 message = mono_string_to_utf8 (str);
4063 free_message = TRUE;
4068 * g_printerr ("\nUnhandled Exception: %s.%s: %s\n", exc->vtable->klass->name_space,
4069 * exc->vtable->klass->name, message);
4071 g_printerr ("\nUnhandled Exception: %s\n", message);
4073 if (free_message)
4074 g_free (message);
4078 * mono_delegate_ctor:
4079 * @this: pointer to an uninitialized delegate object
4080 * @target: target object
4081 * @addr: pointer to native code
4083 * This is used to initialize a delegate. We also insert the method_info if
4084 * we find the info with mono_jit_info_table_find().
4086 void
4087 mono_delegate_ctor (MonoObject *this, MonoObject *target, gpointer addr)
4089 MonoDomain *domain = mono_domain_get ();
4090 MonoDelegate *delegate = (MonoDelegate *)this;
4091 MonoMethod *method = NULL;
4092 MonoClass *class;
4093 MonoJitInfo *ji;
4095 g_assert (this);
4096 g_assert (addr);
4098 class = this->vtable->klass;
4100 if ((ji = mono_jit_info_table_find (domain, mono_get_addr_from_ftnptr (addr)))) {
4101 method = ji->method;
4102 MONO_OBJECT_SETREF (delegate, method_info, mono_method_get_object (domain, method, NULL));
4105 if (target && target->vtable->klass == mono_defaults.transparent_proxy_class) {
4106 g_assert (method);
4107 method = mono_marshal_get_remoting_invoke (method);
4108 delegate->method_ptr = mono_compile_method (method);
4109 MONO_OBJECT_SETREF (delegate, target, target);
4110 } else if (mono_method_signature (method)->hasthis && method->klass->valuetype) {
4111 method = mono_marshal_get_unbox_wrapper (method);
4112 delegate->method_ptr = mono_compile_method (method);
4113 MONO_OBJECT_SETREF (delegate, target, target);
4114 } else {
4115 if (method) {
4117 * Replace the original trampoline with a delegate trampoline
4118 * which will patch delegate->method_ptr with the address of the
4119 * compiled method.
4121 addr = arch_create_delegate_trampoline (method, addr);
4123 delegate->method_ptr = addr;
4124 MONO_OBJECT_SETREF (delegate, target, target);
4129 * mono_method_call_message_new:
4130 * @method: method to encapsulate
4131 * @params: parameters to the method
4132 * @invoke: optional, delegate invoke.
4133 * @cb: async callback delegate.
4134 * @state: state passed to the async callback.
4136 * Translates arguments pointers into a MonoMethodMessage.
4138 MonoMethodMessage *
4139 mono_method_call_message_new (MonoMethod *method, gpointer *params, MonoMethod *invoke,
4140 MonoDelegate **cb, MonoObject **state)
4142 MonoDomain *domain = mono_domain_get ();
4143 MonoMethodSignature *sig = mono_method_signature (method);
4144 MonoMethodMessage *msg;
4145 int i, count, type;
4147 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4149 if (invoke) {
4150 mono_message_init (domain, msg, mono_method_get_object (domain, invoke, NULL), NULL);
4151 count = sig->param_count - 2;
4152 } else {
4153 mono_message_init (domain, msg, mono_method_get_object (domain, method, NULL), NULL);
4154 count = sig->param_count;
4157 for (i = 0; i < count; i++) {
4158 gpointer vpos;
4159 MonoClass *class;
4160 MonoObject *arg;
4162 if (sig->params [i]->byref)
4163 vpos = *((gpointer *)params [i]);
4164 else
4165 vpos = params [i];
4167 type = sig->params [i]->type;
4168 class = mono_class_from_mono_type (sig->params [i]);
4170 if (class->valuetype)
4171 arg = mono_value_box (domain, class, vpos);
4172 else
4173 arg = *((MonoObject **)vpos);
4175 mono_array_setref (msg->args, i, arg);
4178 if (cb != NULL && state != NULL) {
4179 *cb = *((MonoDelegate **)params [i]);
4180 i++;
4181 *state = *((MonoObject **)params [i]);
4184 return msg;
4188 * mono_method_return_message_restore:
4190 * Restore results from message based processing back to arguments pointers
4192 void
4193 mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoArray *out_args)
4195 MonoMethodSignature *sig = mono_method_signature (method);
4196 int i, j, type, size, out_len;
4198 if (out_args == NULL)
4199 return;
4200 out_len = mono_array_length (out_args);
4201 if (out_len == 0)
4202 return;
4204 for (i = 0, j = 0; i < sig->param_count; i++) {
4205 MonoType *pt = sig->params [i];
4207 if (pt->byref) {
4208 char *arg;
4209 if (j >= out_len)
4210 mono_raise_exception (mono_get_exception_execution_engine ("The proxy call returned an incorrect number of output arguments"));
4212 arg = mono_array_get (out_args, gpointer, j);
4213 type = pt->type;
4215 switch (type) {
4216 case MONO_TYPE_VOID:
4217 g_assert_not_reached ();
4218 break;
4219 case MONO_TYPE_U1:
4220 case MONO_TYPE_I1:
4221 case MONO_TYPE_BOOLEAN:
4222 case MONO_TYPE_U2:
4223 case MONO_TYPE_I2:
4224 case MONO_TYPE_CHAR:
4225 case MONO_TYPE_U4:
4226 case MONO_TYPE_I4:
4227 case MONO_TYPE_I8:
4228 case MONO_TYPE_U8:
4229 case MONO_TYPE_R4:
4230 case MONO_TYPE_R8:
4231 case MONO_TYPE_VALUETYPE: {
4232 if (arg) {
4233 size = mono_class_value_size (((MonoObject*)arg)->vtable->klass, NULL);
4234 memcpy (*((gpointer *)params [i]), arg + sizeof (MonoObject), size);
4236 else {
4237 size = mono_class_value_size (mono_class_from_mono_type (pt), NULL);
4238 memset (*((gpointer *)params [i]), 0, size);
4240 break;
4242 case MONO_TYPE_STRING:
4243 case MONO_TYPE_CLASS:
4244 case MONO_TYPE_ARRAY:
4245 case MONO_TYPE_SZARRAY:
4246 case MONO_TYPE_OBJECT:
4247 **((MonoObject ***)params [i]) = (MonoObject *)arg;
4248 break;
4249 default:
4250 g_assert_not_reached ();
4253 j++;
4259 * mono_load_remote_field:
4260 * @this: pointer to an object
4261 * @klass: klass of the object containing @field
4262 * @field: the field to load
4263 * @res: a storage to store the result
4265 * This method is called by the runtime on attempts to load fields of
4266 * transparent proxy objects. @this points to such TP, @klass is the class of
4267 * the object containing @field. @res is a storage location which can be
4268 * used to store the result.
4270 * Returns: an address pointing to the value of field.
4272 gpointer
4273 mono_load_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer *res)
4275 static MonoMethod *getter = NULL;
4276 MonoDomain *domain = mono_domain_get ();
4277 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
4278 MonoClass *field_class;
4279 MonoMethodMessage *msg;
4280 MonoArray *out_args;
4281 MonoObject *exc;
4282 char* full_name;
4284 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
4285 g_assert (res != NULL);
4287 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4288 mono_field_get_value (tp->rp->unwrapped_server, field, res);
4289 return res;
4292 if (!getter) {
4293 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
4294 g_assert (getter);
4297 field_class = mono_class_from_mono_type (field->type);
4299 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4300 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
4301 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
4303 full_name = mono_type_get_full_name (klass);
4304 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
4305 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
4306 g_free (full_name);
4308 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
4310 if (exc) mono_raise_exception ((MonoException *)exc);
4312 if (mono_array_length (out_args) == 0)
4313 return NULL;
4315 *res = mono_array_get (out_args, MonoObject *, 0); /* FIXME: GC write abrrier for res */
4317 if (field_class->valuetype) {
4318 return ((char *)*res) + sizeof (MonoObject);
4319 } else
4320 return res;
4324 * mono_load_remote_field_new:
4325 * @this:
4326 * @klass:
4327 * @field:
4329 * Missing documentation.
4331 MonoObject *
4332 mono_load_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field)
4334 static MonoMethod *getter = NULL;
4335 MonoDomain *domain = mono_domain_get ();
4336 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
4337 MonoClass *field_class;
4338 MonoMethodMessage *msg;
4339 MonoArray *out_args;
4340 MonoObject *exc, *res;
4341 char* full_name;
4343 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
4345 field_class = mono_class_from_mono_type (field->type);
4347 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4348 gpointer val;
4349 if (field_class->valuetype) {
4350 res = mono_object_new (domain, field_class);
4351 val = ((gchar *) res) + sizeof (MonoObject);
4352 } else {
4353 val = &res;
4355 mono_field_get_value (tp->rp->unwrapped_server, field, val);
4356 return res;
4359 if (!getter) {
4360 getter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldGetter", -1);
4361 g_assert (getter);
4364 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4365 out_args = mono_array_new (domain, mono_defaults.object_class, 1);
4367 mono_message_init (domain, msg, mono_method_get_object (domain, getter, NULL), out_args);
4369 full_name = mono_type_get_full_name (klass);
4370 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
4371 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
4372 g_free (full_name);
4374 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
4376 if (exc) mono_raise_exception ((MonoException *)exc);
4378 if (mono_array_length (out_args) == 0)
4379 res = NULL;
4380 else
4381 res = mono_array_get (out_args, MonoObject *, 0);
4383 return res;
4387 * mono_store_remote_field:
4388 * @this: pointer to an object
4389 * @klass: klass of the object containing @field
4390 * @field: the field to load
4391 * @val: the value/object to store
4393 * This method is called by the runtime on attempts to store fields of
4394 * transparent proxy objects. @this points to such TP, @klass is the class of
4395 * the object containing @field. @val is the new value to store in @field.
4397 void
4398 mono_store_remote_field (MonoObject *this, MonoClass *klass, MonoClassField *field, gpointer val)
4400 static MonoMethod *setter = NULL;
4401 MonoDomain *domain = mono_domain_get ();
4402 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
4403 MonoClass *field_class;
4404 MonoMethodMessage *msg;
4405 MonoArray *out_args;
4406 MonoObject *exc;
4407 MonoObject *arg;
4408 char* full_name;
4410 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
4412 field_class = mono_class_from_mono_type (field->type);
4414 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4415 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, val);
4416 else mono_field_set_value (tp->rp->unwrapped_server, field, *((MonoObject **)val));
4417 return;
4420 if (!setter) {
4421 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
4422 g_assert (setter);
4425 if (field_class->valuetype)
4426 arg = mono_value_box (domain, field_class, val);
4427 else
4428 arg = *((MonoObject **)val);
4431 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4432 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
4434 full_name = mono_type_get_full_name (klass);
4435 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
4436 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
4437 mono_array_setref (msg->args, 2, arg);
4438 g_free (full_name);
4440 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
4442 if (exc) mono_raise_exception ((MonoException *)exc);
4446 * mono_store_remote_field_new:
4447 * @this:
4448 * @klass:
4449 * @field:
4450 * @arg:
4452 * Missing documentation
4454 void
4455 mono_store_remote_field_new (MonoObject *this, MonoClass *klass, MonoClassField *field, MonoObject *arg)
4457 static MonoMethod *setter = NULL;
4458 MonoDomain *domain = mono_domain_get ();
4459 MonoTransparentProxy *tp = (MonoTransparentProxy *) this;
4460 MonoClass *field_class;
4461 MonoMethodMessage *msg;
4462 MonoArray *out_args;
4463 MonoObject *exc;
4464 char* full_name;
4466 g_assert (this->vtable->klass == mono_defaults.transparent_proxy_class);
4468 field_class = mono_class_from_mono_type (field->type);
4470 if (tp->remote_class->proxy_class->contextbound && tp->rp->context == (MonoObject *) mono_context_get ()) {
4471 if (field_class->valuetype) mono_field_set_value (tp->rp->unwrapped_server, field, ((gchar *) arg) + sizeof (MonoObject));
4472 else mono_field_set_value (tp->rp->unwrapped_server, field, arg);
4473 return;
4476 if (!setter) {
4477 setter = mono_class_get_method_from_name (mono_defaults.object_class, "FieldSetter", -1);
4478 g_assert (setter);
4481 msg = (MonoMethodMessage *)mono_object_new (domain, mono_defaults.mono_method_message_class);
4482 mono_message_init (domain, msg, mono_method_get_object (domain, setter, NULL), NULL);
4484 full_name = mono_type_get_full_name (klass);
4485 mono_array_setref (msg->args, 0, mono_string_new (domain, full_name));
4486 mono_array_setref (msg->args, 1, mono_string_new (domain, field->name));
4487 mono_array_setref (msg->args, 2, arg);
4488 g_free (full_name);
4490 mono_remoting_invoke ((MonoObject *)(tp->rp), msg, &exc, &out_args);
4492 if (exc) mono_raise_exception ((MonoException *)exc);
4496 * mono_get_addr_from_ftnptr:
4498 * Given a pointer to a function descriptor, return the function address.
4499 * This is only needed on IA64.
4501 gpointer
4502 mono_get_addr_from_ftnptr (gpointer descr)
4504 #ifdef __ia64__
4505 return *(gpointer*)descr;
4506 #else
4507 return descr;
4508 #endif
4511 #if 0
4513 * mono_string_chars:
4514 * @s: a MonoString
4516 * Returns a pointer to the UCS16 characters stored in the MonoString
4518 gunichar2 *
4519 mono_string_chars(MonoString *s)
4521 /* This method is here only for documentation extraction, this is a macro */
4525 * mono_string_length:
4526 * @s: MonoString
4528 * Returns the lenght in characters of the string
4531 mono_string_length (MonoString *s)
4533 /* This method is here only for documentation extraction, this is a macro */
4536 #endif