2004-07-05 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mono / metadata / object.c
index 932a95ad1e384b62e3c052513d3fcb5a30b9fc5d..bdf832baa6dcb0a122d98130410123ff6c39076e 100644 (file)
 #include <mono/metadata/object.h>
 #include <mono/metadata/gc-internal.h>
 #include <mono/metadata/exception.h>
-#include <mono/metadata/appdomain.h>
+#include <mono/metadata/domain-internals.h>
+#include "mono/metadata/metadata-internals.h"
+#include "mono/metadata/class-internals.h"
 #include <mono/metadata/assembly.h>
 #include <mono/metadata/threadpool.h>
 #include <mono/metadata/marshal.h>
 #include "mono/metadata/debug-helpers.h"
 #include "mono/metadata/marshal.h"
 #include <mono/metadata/threads.h>
+#include <mono/metadata/threads-types.h>
 #include <mono/metadata/environment.h>
 #include "mono/metadata/profiler-private.h"
 #include <mono/os/gc_wrapper.h>
@@ -55,6 +58,8 @@ mono_runtime_object_init (MonoObject *this)
 
        g_assert (method);
 
+       if (method->klass->valuetype)
+               this = mono_object_unbox (this);
        mono_runtime_invoke (method, this, NULL, NULL);
 }
 
@@ -352,7 +357,7 @@ mono_class_compute_gc_descriptor (MonoClass *class)
 
                /* GC 6.1 has trouble handling 64 bit descriptors... */
                if ((class->instance_size / sizeof (gpointer)) > 30) {
-//                     printf ("TOO LARGE: %s %d.\n", class->name, class->instance_size / sizeof (gpointer));
+/*                     printf ("TOO LARGE: %s %d.\n", class->name, class->instance_size / sizeof (gpointer)); */
                        return;
                }
 
@@ -360,10 +365,10 @@ mono_class_compute_gc_descriptor (MonoClass *class)
 
                count ++;
 
-//             if (count > 442)
-//                     return;
+/*             if (count > 442) */
+/*                     return;  */
 
-//             printf("KLASS: %s.\n", class->name);
+/*             printf("KLASS: %s.\n", class->name); */
 
                for (p = class; p != NULL; p = p->parent) {
                for (i = 0; i < p->field.count; ++i) {
@@ -391,7 +396,7 @@ mono_class_compute_gc_descriptor (MonoClass *class)
                        case MONO_TYPE_U8:
                        case MONO_TYPE_R4:
                        case MONO_TYPE_R8:
-//                             printf ("F: %s %s %d %lld %llx.\n", class->name, field->name, field->offset, ((guint64)1) << pos, bitmap);
+/*                             printf ("F: %s %s %d %lld %llx.\n", class->name, field->name, field->offset, ((guint64)1) << pos, bitmap); */
                                break;
                        case MONO_TYPE_I:
                        case MONO_TYPE_STRING:
@@ -403,7 +408,7 @@ mono_class_compute_gc_descriptor (MonoClass *class)
                                g_assert ((field->offset % sizeof(gpointer)) == 0);
 
                                bitmap |= ((guint64)1) << pos;
-//                             printf ("F: %s %s %d %d %lld %llx.\n", class->name, field->name, field->offset, pos, ((guint64)(1)) << pos, bitmap);
+/*                             printf ("F: %s %s %d %d %lld %llx.\n", class->name, field->name, field->offset, pos, ((guint64)(1)) << pos, bitmap); */
                                break;
                        case MONO_TYPE_VALUETYPE: {
                                MonoClass *fclass = field->type->data.klass;
@@ -419,7 +424,7 @@ mono_class_compute_gc_descriptor (MonoClass *class)
                }
                }
 
-//             printf("CLASS: %s.%s -> %d %llx.\n", class->name_space, class->name, class->instance_size / sizeof (gpointer), bitmap);
+/*             printf("CLASS: %s.%s -> %d %llx.\n", class->name_space, class->name, class->instance_size / sizeof (gpointer), bitmap); */
                class->gc_bitmap = bitmap;
                /* Convert to the format expected by GC_make_descriptor */
                bm [0] = (guint32)bitmap;
@@ -507,7 +512,7 @@ mono_class_vtable (MonoDomain *domain, MonoClass *class)
 
 #if CREATION_SPEEDUP
        mono_class_compute_gc_descriptor (class);
-       if (domain != mono_root_domain)
+       if (domain != mono_get_root_domain ())
                /*
                 * We can't use typed allocation in the non-root domains, since the
                 * collector needs the GC descriptor stored in the vtable even after
@@ -903,8 +908,10 @@ void mono_upgrade_remote_class (MonoDomain *domain, MonoRemoteClass *remote_clas
        mono_domain_unlock (domain);
 }
 
-/*
- * Retrieve the MonoMethod that would to be called on obj if obj is passed as
+/**
+ * mono_object_get_virtual_method:
+ *
+ * Retrieve the MonoMethod that would be called on obj if obj is passed as
  * the instance of a callvirt of method.
  */
 MonoMethod*
@@ -955,6 +962,36 @@ dummy_mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObj
 
 static MonoInvokeFunc default_mono_runtime_invoke = dummy_mono_runtime_invoke;
 
+/**
+ * mono_runtime_invoke:
+ *
+ * Invokes the method represented by `method' on the object `obj'.
+ *
+ * obj is the 'this' pointer, it should be NULL for static
+ * methods, a MonoObject* for object instances and a pointer to
+ * the value type for value types.
+ *
+ * The params array contains the arguments to the method with the
+ * same convention: MonoObject* pointers for object instances and
+ * pointers to the value type otherwise. 
+ * 
+ * From unmanaged code you'll usually use the
+ * mono_runtime_invoke() variant.
+ *
+ * Note that this function doesn't handle virtual methods for
+ * you, it will exec the exact method you pass: we still need to
+ * expose a function to lookup the derived class implementation
+ * of a virtual method (there are examples of this in the code,
+ * though).
+ * 
+ * You can pass NULL as the exc argument if you don't want to
+ * catch exceptions, otherwise, *exc will be set to the exception
+ * thrown, if any.  if an exception is thrown, you can't use the
+ * MonoObject* result from the function.
+ * 
+ * If the method returns a value type, it is boxed in an object
+ * reference.
+ */
 MonoObject*
 mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
 {
@@ -1220,7 +1257,7 @@ fire_process_exit_event (void)
        field = mono_class_get_field_from_name (mono_defaults.appdomain_class, "ProcessExit");
        g_assert (field);
 
-       if (domain != mono_root_domain)
+       if (domain != mono_get_root_domain ())
                return;
 
        delegate = *(MonoObject **)(((char *)domain->domain) + field->offset); 
@@ -1381,7 +1418,7 @@ mono_unhandled_exception (MonoObject *exc)
                /* set exitcode only in the main thread */
                if (mono_thread_current () == main_thread)
                        mono_environment_exitcode_set (1);
-               if (domain != mono_root_domain || !delegate) {
+               if (domain != mono_get_root_domain () || !delegate) {
                        mono_print_unhandled_exception (exc);
                } else {
                        MonoObject *e = NULL;
@@ -1438,11 +1475,14 @@ mono_runtime_exec_main (MonoMethod *method, MonoArray *args, MonoObject **exc)
        if (!domain->entry_assembly) {
                gchar *str;
                gchar *config_suffix;
+               MonoAssembly *assembly;
 
-               domain->entry_assembly = method->klass->image->assembly;
-               ves_icall_System_AppDomainSetup_InitAppDomainSetup (domain->setup);
-               config_suffix = g_strconcat (domain->entry_assembly->aname.name, ".exe.config", NULL);
-               str = g_build_filename (domain->entry_assembly->basedir, config_suffix, NULL);
+               assembly = method->klass->image->assembly;
+               domain->entry_assembly = assembly;
+               domain->setup->application_base = mono_string_new (domain, assembly->basedir);
+
+               config_suffix = g_strconcat (assembly->aname.name, ".exe.config", NULL);
+               str = g_build_filename (assembly->basedir, config_suffix, NULL);
                g_free (config_suffix);
                domain->setup->configuration_file = mono_string_new (domain, str);
                g_free (str);
@@ -1482,6 +1522,39 @@ mono_install_runtime_invoke (MonoInvokeFunc func)
        default_mono_runtime_invoke = func ? func: dummy_mono_runtime_invoke;
 }
 
+/**
+ * mono_runtime_invoke:
+ *
+ * Invokes the method represented by `method' on the object `obj'.
+ *
+ * obj is the 'this' pointer, it should be NULL for static
+ * methods, a MonoObject* for object instances and a pointer to
+ * the value type for value types.
+ *
+ * The params array contains the arguments to the method with the
+ * same convention: MonoObject* pointers for object instances and
+ * pointers to the value type otherwise. The _invoke_array
+ * variant takes a C# object[] as the params argument (MonoArray
+ * *params): in this case the value types are boxed inside the
+ * respective reference representation.
+ * 
+ * From unmanaged code you'll usually use the
+ * mono_runtime_invoke() variant.
+ *
+ * Note that this function doesn't handle virtual methods for
+ * you, it will exec the exact method you pass: we still need to
+ * expose a function to lookup the derived class implementation
+ * of a virtual method (there are examples of this in the code,
+ * though).
+ * 
+ * You can pass NULL as the exc argument if you don't want to
+ * catch exceptions, otherwise, *exc will be set to the exception
+ * thrown, if any.  if an exception is thrown, you can't use the
+ * MonoObject* result from the function.
+ * 
+ * If the method returns a value type, it is boxed in an object
+ * reference.
+ */
 MonoObject*
 mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
                           MonoObject **exc)
@@ -1513,7 +1586,13 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
                        case MONO_TYPE_R4:
                        case MONO_TYPE_R8:
                        case MONO_TYPE_VALUETYPE:
-                               g_assert (((gpointer*)params->vector) [i]);
+                               if (sig->params [i]->byref) {
+                                       /* MS seems to create the objects if a null is passed in */
+                                       if (! ((gpointer *)params->vector)[i])
+                                               ((gpointer*)params->vector)[i] = mono_object_new (mono_domain_get (), mono_class_from_mono_type (sig->params [i]));
+                               }
+                               else
+                                       g_assert (((gpointer*)params->vector) [i]);
                                pa [i] = (char *)(((gpointer *)params->vector)[i]) + sizeof (MonoObject);
                                break;
                        case MONO_TYPE_STRING:
@@ -1533,16 +1612,23 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params,
        }
 
        if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) {
+               void *o = obj;
                if (!obj) {
                        obj = mono_object_new (mono_domain_get (), method->klass);
                        if (mono_object_class(obj) == mono_defaults.transparent_proxy_class) {
                                method = mono_marshal_get_remoting_invoke (method->slot == -1 ? method : method->klass->vtable [method->slot]);
                        }
+                       if (method->klass->valuetype)
+                               o = mono_object_unbox (obj);
+                       else
+                               o = obj;
                }
-               mono_runtime_invoke (method, obj, pa, exc);
+               mono_runtime_invoke (method, o, pa, exc);
                return obj;
-       } else
+       } else {
+               /* obj must be already unboxed if needed */
                return mono_runtime_invoke (method, obj, pa, exc);
+       }
 }
 
 static void
@@ -1595,31 +1681,14 @@ mono_object_allocate_spec (size_t size, void *gcdescr)
 }
 #endif
 
-/**
- * mono_object_free:
- *
- * Frees the memory used by the object.  Debugging purposes
- * only, as we will have our GC system.
- */
-void
-mono_object_free (MonoObject *o)
-{
-#if HAVE_BOEHM_GC
-       g_error ("mono_object_free called with boehm gc.");
-#else
-       MonoClass *c = o->vtable->klass;
-       
-       memset (o, 0, c->instance_size);
-       free (o);
-#endif
-}
-
 /**
  * mono_object_new:
  * @klass: the class of the object that we want to create
  *
- * Returns: A newly created object whose definition is
- * looked up using @klass
+ * Returns a newly created object whose definition is
+ * looked up using @klass.   This will not invoke any constructors, 
+ * so the consumer of this routine has to invoke any constructors on
+ * its own to initialize the object.
  */
 MonoObject *
 mono_object_new (MonoDomain *domain, MonoClass *klass)
@@ -1684,7 +1753,7 @@ mono_object_new_fast (MonoVTable *vtable)
        if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
                o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
        } else {
-//             printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name);
+/*             printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
                o = mono_object_allocate (vtable->klass->instance_size);
                o->vtable = vtable;
        }
@@ -1704,7 +1773,7 @@ mono_object_new_alloc_specific (MonoVTable *vtable)
        if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
                o = mono_object_allocate_spec (vtable->klass->instance_size, vtable);
        } else {
-//             printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name);
+/*             printf("OBJECT: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
                o = mono_object_allocate (vtable->klass->instance_size);
                o->vtable = vtable;
        }
@@ -1941,7 +2010,7 @@ mono_array_new_specific (MonoVTable *vtable, guint32 n)
        if (vtable->gc_descr != GC_NO_DESCRIPTOR) {
                o = mono_object_allocate_spec (byte_len, vtable);
        } else {
-//             printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name);
+/*             printf("ARRAY: %s.%s.\n", vtable->klass->name_space, vtable->klass->name); */
                o = mono_object_allocate (byte_len);
                o->vtable = vtable;
        }
@@ -1990,18 +2059,23 @@ mono_string_new_size (MonoDomain *domain, gint32 len)
 {
        MonoString *s;
        MonoVTable *vtable;
+       size_t size = (sizeof (MonoString) + ((len + 1) * 2));
+
+       /* overflow ? can't fit it, can't allocate it! */
+       if (len > size)
+               out_of_memory (-1);
 
        vtable = mono_class_vtable (domain, mono_defaults.string_class);
 
 #if CREATION_SPEEDUP
        if (vtable->gc_descr != GC_NO_DESCRIPTOR)
-               s = mono_object_allocate_spec (sizeof (MonoString) + ((len + 1) * 2), vtable);
+               s = mono_object_allocate_spec (size, vtable);
        else {
-               s = (MonoString*)mono_object_allocate (sizeof (MonoString) + ((len + 1) * 2));
+               s = (MonoString*)mono_object_allocate (size);
                s->object.vtable = vtable;
        }
 #else
-       s = (MonoString*)mono_object_allocate (sizeof (MonoString) + ((len + 1) * 2));
+       s = (MonoString*)mono_object_allocate (size);
        s->object.vtable = vtable;
 #endif
 
@@ -2135,10 +2209,23 @@ mono_value_box (MonoDomain *domain, MonoClass *class, gpointer value)
        return res;
 }
 
+MonoDomain*
+mono_object_get_domain (MonoObject *obj)
+{
+       return mono_object_domain (obj);
+}
+
+MonoClass*
+mono_object_get_class (MonoObject *obj)
+{
+       return mono_object_class (obj);
+}
+
 gpointer
 mono_object_unbox (MonoObject *obj)
 {
        /* add assert for valuetypes? */
+       g_assert (obj->vtable->klass->valuetype);
        return ((char*)obj) + sizeof (MonoObject);
 }
 
@@ -2661,7 +2748,7 @@ mono_message_invoke (MonoObject *target, MonoMethodMessage *msg,
                }
        }
 
-       return mono_runtime_invoke_array (method, target, msg->args, exc);
+       return mono_runtime_invoke_array (method, method->klass->valuetype? mono_object_unbox (target): target, msg->args, exc);
 }
 
 void
@@ -2847,6 +2934,7 @@ mono_method_return_message_restore (MonoMethod *method, gpointer *params, MonoAr
                        case MONO_TYPE_CLASS: 
                        case MONO_TYPE_ARRAY:
                        case MONO_TYPE_SZARRAY:
+                       case MONO_TYPE_OBJECT:
                                **((MonoObject ***)params [i]) = (MonoObject *)arg;
                                break;
                        default: