2008-10-07 Gonzalo Paniagua Javier <gonzalo@novell.com>
[mono.git] / mono / metadata / icall.c
index 9f06679294636f2f40e71dc313aba830acb22d71..1eac41241ed6fbc1b6fdfaa602f6fd67d122687c 100644 (file)
@@ -24,6 +24,7 @@
 #include <stdlib.h>
 #endif
 
+#include "mono/utils/mono-membar.h"
 #include <mono/metadata/object.h>
 #include <mono/metadata/threads.h>
 #include <mono/metadata/threads-types.h>
@@ -983,6 +984,9 @@ ves_icall_System_ValueType_Equals (MonoObject *this, MonoObject *that, MonoArray
 
        klass = mono_object_class (this);
 
+       if (klass->enumtype && klass->enum_basetype && klass->enum_basetype->type == MONO_TYPE_I4)
+               return (*(gint32*)((guint8*)this + sizeof (MonoObject)) == *(gint32*)((guint8*)that + sizeof (MonoObject)));
+
        /*
         * Do the comparison for fields of primitive type and return a result if
         * possible. Otherwise, return the remaining fields in an array to the 
@@ -998,10 +1002,38 @@ ves_icall_System_ValueType_Equals (MonoObject *this, MonoObject *that, MonoArray
                        continue;
                /* FIXME: Add more types */
                switch (field->type->type) {
+               case MONO_TYPE_U1:
+               case MONO_TYPE_I1:
+               case MONO_TYPE_BOOLEAN:
+                       if (*((guint8*)this + field->offset) != *((guint8*)that + field->offset))
+                               return FALSE;
+                       break;
+               case MONO_TYPE_U2:
+               case MONO_TYPE_I2:
+               case MONO_TYPE_CHAR:
+                       if (*(gint16*)((guint8*)this + field->offset) != *(gint16*)((guint8*)that + field->offset))
+                               return FALSE;
+                       break;
+               case MONO_TYPE_U4:
                case MONO_TYPE_I4:
                        if (*(gint32*)((guint8*)this + field->offset) != *(gint32*)((guint8*)that + field->offset))
                                return FALSE;
                        break;
+               case MONO_TYPE_U8:
+               case MONO_TYPE_I8:
+                       if (*(gint64*)((guint8*)this + field->offset) != *(gint64*)((guint8*)that + field->offset))
+                               return FALSE;
+                       break;
+               case MONO_TYPE_R4:
+                       if (*(float*)((guint8*)this + field->offset) != *(float*)((guint8*)that + field->offset))
+                               return FALSE;
+                       break;
+               case MONO_TYPE_R8:
+                       if (*(double*)((guint8*)this + field->offset) != *(double*)((guint8*)that + field->offset))
+                               return FALSE;
+                       break;
+
+
                case MONO_TYPE_STRING: {
                        MonoString *s1, *s2;
                        guint32 s1len, s2len;
@@ -2698,6 +2730,23 @@ ves_icall_MonoGenericClass_GetEvents (MonoReflectionGenericClass *type,
        return res;
 }
 
+static MonoReflectionType*
+ves_icall_MonoGenericClass_InflateType (MonoReflectionGenericClass *type,
+                                     MonoReflectionType *target)
+{
+       MonoType *res_type;
+       MonoClass *gklass;
+       MonoReflectionType *res;
+
+       MONO_ARCH_SAVE_REGS;
+
+       gklass = mono_class_from_mono_type (type->type.type);
+       res_type = mono_class_inflate_generic_type (target->type, mono_class_get_context (gklass));
+       res = mono_type_get_object (mono_object_domain (type), res_type);
+       mono_metadata_free_type (res_type);
+       return res;
+}
+
 static MonoReflectionMethod *
 ves_icall_MonoType_get_DeclaringMethod (MonoReflectionType *type)
 {
@@ -2952,7 +3001,7 @@ ves_icall_InternalInvoke (MonoReflectionMethod *method, MonoObject *this, MonoAr
        }
 
        if ((m->klass->flags & TYPE_ATTRIBUTE_ABSTRACT) && !strcmp (m->name, ".ctor") && !this) {
-               *exc = mono_exception_from_name_msg (mono_defaults.corlib, "System", "MethodAccessException", "Cannot invoke constructor of an abstract class.");
+               *exc = mono_exception_from_name_msg (mono_defaults.corlib, "System.Reflection", "TargetException", "Cannot invoke constructor of an abstract class.");
                return NULL;
        }
 
@@ -3228,6 +3277,47 @@ ves_icall_System_Enum_get_value (MonoObject *this)
        return res;
 }
 
+static MonoReflectionType *
+ves_icall_System_Enum_get_underlying_type (MonoReflectionType *type)
+{
+       MONO_ARCH_SAVE_REGS;
+
+       return mono_type_get_object (mono_object_domain (type), mono_class_from_mono_type (type->type)->enum_basetype);
+}
+
+static int
+ves_icall_System_Enum_get_hashcode (MonoObject *this)
+{
+       gpointer data = (char *)this + sizeof (MonoObject);
+       MonoType *basetype = this->vtable->klass->enum_basetype;
+       g_assert (basetype);
+
+       switch (basetype->type) {
+               case MONO_TYPE_I1:      
+                       return *((gint8*)data);
+               case MONO_TYPE_U1:
+                       return *((guint8*)data);
+               case MONO_TYPE_CHAR:
+               case MONO_TYPE_U2:
+                       return *((guint16*)data);
+               
+               case MONO_TYPE_I2:
+                       return *((gint16*)data);
+               case MONO_TYPE_U4:
+                       return *((guint32*)data);
+               case MONO_TYPE_I4:
+                       return *((gint32*)data);
+               case MONO_TYPE_U8:
+               case MONO_TYPE_I8: {
+                       gint64 value = *((gint64*)data);
+                       return (gint)(value & 0xffffffff) ^ (int)(value >> 32);
+               }
+               default:
+                       g_error ("Implement type 0x%02x in get_hashcode", basetype->type);
+       }
+       return 0;
+}
+
 static void
 ves_icall_get_enum_info (MonoReflectionType *type, MonoEnumInfo *info)
 {
@@ -3477,6 +3567,7 @@ method_nonpublic (MonoMethod* method, gboolean start_klass)
 static MonoArray*
 ves_icall_Type_GetMethodsByName (MonoReflectionType *type, MonoString *name, guint32 bflags, MonoBoolean ignore_case, MonoReflectionType *reftype)
 {
+       static MonoClass *MethodInfo_array;
        MonoDomain *domain; 
        MonoClass *startklass, *klass, *refklass;
        MonoArray *res;
@@ -3488,12 +3579,20 @@ ves_icall_Type_GetMethodsByName (MonoReflectionType *type, MonoString *name, gui
        guint32 *method_slots;
        gchar *mname = NULL;
        int (*compare_func) (const char *s1, const char *s2) = NULL;
+       MonoVTable *array_vtable;
                
        MONO_ARCH_SAVE_REGS;
 
+       if (!MethodInfo_array) {
+               MonoClass *klass = mono_array_class_get (mono_defaults.method_info_class, 1);
+               mono_memory_barrier ();
+               MethodInfo_array = klass;
+       }
+
        domain = ((MonoObject *)type)->vtable->domain;
+       array_vtable = mono_class_vtable (domain, MethodInfo_array);
        if (type->type->byref)
-               return mono_array_new (domain, mono_defaults.method_info_class, 0);
+               return mono_array_new_specific (array_vtable, 0);
        klass = startklass = mono_class_from_mono_type (type->type);
        refklass = mono_class_from_mono_type (reftype->type);
        len = 0;
@@ -3516,7 +3615,7 @@ ves_icall_Type_GetMethodsByName (MonoReflectionType *type, MonoString *name, gui
        }
        i = 0;
        len = 1;
-       res = mono_array_new (domain, mono_defaults.method_info_class, len);
+       res = mono_array_new_specific (array_vtable, len);
 handle_parent:
        mono_class_setup_vtable (klass);
        if (klass->exception_type != MONO_EXCEPTION_NONE)
@@ -3564,7 +3663,7 @@ handle_parent:
                member = (MonoObject*)mono_method_get_object (domain, method, refklass);
                
                if (i >= len) {
-                       MonoArray *new_res = mono_array_new (domain, mono_defaults.method_info_class, len * 2);
+                       MonoArray *new_res = mono_array_new_specific (array_vtable, len * 2);
                        mono_array_memcpy_refs (new_res, 0, res, 0, len);
                        len *= 2;
                        res = new_res;
@@ -3985,8 +4084,8 @@ ves_icall_Type_GetNestedType (MonoReflectionType *type, MonoString *name, guint3
        MonoDomain *domain; 
        MonoClass *klass;
        MonoClass *nested;
-       GList *tmpn;
        char *str;
+       gpointer iter;
        
        MONO_ARCH_SAVE_REGS;
 
@@ -4012,9 +4111,9 @@ ves_icall_Type_GetNestedType (MonoReflectionType *type, MonoString *name, guint3
        if (klass->generic_class)
                klass = klass->generic_class->container_class;
 
-       for (tmpn = klass->nested_classes; tmpn; tmpn = tmpn->next) {
+       iter = NULL;
+       while ((nested = mono_class_get_nested_types (klass, &iter))) {
                int match = 0;
-               nested = tmpn->data;
                if ((nested->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK) == TYPE_ATTRIBUTE_NESTED_PUBLIC) {
                        if (bflags & BFLAGS_Public)
                                match++;
@@ -4039,12 +4138,12 @@ static MonoArray*
 ves_icall_Type_GetNestedTypes (MonoReflectionType *type, guint32 bflags)
 {
        MonoDomain *domain; 
-       GList *tmpn;
        MonoClass *klass;
        MonoArray *res;
        MonoObject *member;
        int i, len, match;
        MonoClass *nested;
+       gpointer iter;
 
        MONO_ARCH_SAVE_REGS;
 
@@ -4070,9 +4169,9 @@ ves_icall_Type_GetNestedTypes (MonoReflectionType *type, guint32 bflags)
        i = 0;
        len = 1;
        res = mono_array_new (domain, mono_defaults.monotype_class, len);
-       for (tmpn = klass->nested_classes; tmpn; tmpn = tmpn->next) {
+       iter = NULL;
+       while ((nested = mono_class_get_nested_types (klass, &iter))) {
                match = 0;
-               nested = tmpn->data;
                if ((nested->flags & TYPE_ATTRIBUTE_VISIBILITY_MASK) == TYPE_ATTRIBUTE_NESTED_PUBLIC) {
                        if (bflags & BFLAGS_Public)
                                match++;
@@ -4218,13 +4317,36 @@ ves_icall_System_Reflection_Assembly_get_code_base (MonoReflectionAssembly *asse
        MonoString *res = NULL;
        gchar *uri;
        gchar *absolute;
+       gchar *dyn_base;
+       gchar *shadow_ini_file;
+       gsize len;
        
        MONO_ARCH_SAVE_REGS;
 
-       if (g_path_is_absolute (mass->image->name))
+       absolute = NULL;
+       /* Check for shadow-copied assembly */
+       if (domain->setup->dynamic_base != NULL) {
+               dyn_base = mono_string_to_utf8 (domain->setup->dynamic_base);
+               if (!strncmp (dyn_base, mass->basedir, strlen (dyn_base))) {
+                       shadow_ini_file = g_build_filename (mass->basedir, "__AssemblyInfo__.ini", NULL);
+                       if (!g_file_get_contents (shadow_ini_file, &absolute, &len, NULL) ||
+                               !g_file_test (absolute, G_FILE_TEST_IS_REGULAR)) {
+                               if (absolute) {
+                                       g_free (absolute);
+                                       absolute = NULL;
+                               }
+                       }
+                       g_free (shadow_ini_file);
+               }
+               g_free (dyn_base);
+               /* 'absolute' contains the original location of the shadow-copied assembly or NULL */
+       }
+
+       if (absolute == NULL && g_path_is_absolute (mass->image->name))
                absolute = g_strdup (mass->image->name);
-       else
+       else if (absolute == NULL) 
                absolute = g_build_filename (mass->basedir, mass->image->name, NULL);
+
 #if PLATFORM_WIN32
        {
                gint i;
@@ -4236,7 +4358,16 @@ ves_icall_System_Reflection_Assembly_get_code_base (MonoReflectionAssembly *asse
        if (escaped) {
                uri = g_filename_to_uri (absolute, NULL, NULL);
        } else {
-               uri = g_strconcat ("file://", absolute, NULL);
+               const char *prepend = "file://";
+#if PLATFORM_WIN32
+               if (*absolute == '/' && *(absolute + 1) == '/') {
+                       prepend = "file:";
+               } else {
+                       prepend = "file:///";
+               }
+#else
+               uri = g_strconcat (prepend, absolute, NULL);
+#endif
        }
 
        if (uri) {
@@ -4424,7 +4555,7 @@ ves_icall_System_Reflection_Assembly_GetReferencedAssemblies (MonoReflectionAsse
 
                if (create_culture) {
                        gpointer args [2];
-                       gboolean assembly_ref = TRUE;
+                       MonoBoolean assembly_ref = 1;
                        args [0] = mono_string_new (domain, mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_CULTURE]));
                        args [1] = &assembly_ref;
                        MONO_OBJECT_SETREF (aname, cultureInfo, mono_runtime_invoke (create_culture, NULL, args, NULL));
@@ -4736,7 +4867,7 @@ mono_method_get_equivalent_method (MonoMethod *method, MonoClass *klass)
 {
        int offset = -1, i;
        if (method->is_inflated && ((MonoMethodInflated*)method)->context.method_inst) {
-               MonoMethodInflated *inflated = method;
+               MonoMethodInflated *inflated = (MonoMethodInflated*)method;
                //method is inflated, we should inflate it on the other class
                MonoGenericContext ctx;
                ctx.method_inst = inflated->context.method_inst;
@@ -4864,7 +4995,7 @@ fill_reflection_assembly_name (MonoDomain *domain, MonoReflectionAssemblyName *a
        guint32 pkey_len;
        const char *pkey_ptr;
        gchar *codebase;
-       gboolean assembly_ref = FALSE;
+       MonoBoolean assembly_ref = 0;
 
        MONO_ARCH_SAVE_REGS;
 
@@ -5715,12 +5846,9 @@ ves_icall_System_Delegate_CreateDelegate_internal (MonoReflectionType *type, Mon
 
        delegate = mono_object_new (mono_object_domain (type), delegate_class);
 
-       g_assert (!method->klass->generic_container);
-       /* FIXME: only do this for methods which can be shared! */
-       if ((method->is_inflated && mono_method_get_context (method)->method_inst &&
-                                       mono_class_generic_sharing_enabled (method->klass)) ||
-                       ((method->flags & METHOD_ATTRIBUTE_STATIC) && method->klass->generic_class)) {
-               func = mono_compile_method (mono_marshal_get_static_rgctx_invoke (method));
+       if (mono_method_needs_static_rgctx_invoke (method, FALSE)) {
+               method = mono_marshal_get_static_rgctx_invoke (method);
+               func = mono_compile_method (method);
        } else if (method->dynamic) {
                /* Creating a trampoline would leak memory */
                func = mono_compile_method (method);
@@ -5729,7 +5857,7 @@ ves_icall_System_Delegate_CreateDelegate_internal (MonoReflectionType *type, Mon
                        mono_runtime_create_jump_trampoline (mono_domain_get (), method, TRUE));
        }
 
-       mono_delegate_ctor (delegate, target, func);
+       mono_delegate_ctor_with_method (delegate, target, func, method);
 
        return delegate;
 }
@@ -7657,6 +7785,8 @@ type_from_typename (char *typename)
                klass = mono_defaults.object_class;
        else if (!strcmp (typename, "obj"))
                klass = mono_defaults.object_class;
+       else if (!strcmp (typename, "string"))
+               klass = mono_defaults.string_class;
        else if (!strcmp (typename, "bool"))
                klass = mono_defaults.boolean_class;
        else if (!strcmp (typename, "boolean"))
@@ -7742,6 +7872,18 @@ mono_find_jit_icall_by_addr (gconstpointer addr)
        return info;
 }
 
+/*
+ * mono_get_jit_icall_info:
+ *
+ *   Return the hashtable mapping JIT icall names to MonoJitICallInfo structures. The
+ * caller should access it while holding the loader lock.
+ */
+GHashTable*
+mono_get_jit_icall_info (void)
+{
+       return jit_icall_hash_name;
+}
+
 void
 mono_register_jit_icall_wrapper (MonoJitICallInfo *info, gconstpointer wrapper)
 {